2016-08-17 15:08:22 +00:00
|
|
|
/*
|
|
|
|
FreeRTOS V8.2.0 - Copyright (C) 2015 Real Time Engineers Ltd.
|
|
|
|
All rights reserved
|
|
|
|
|
|
|
|
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
|
|
|
|
|
|
|
This file is part of the FreeRTOS distribution.
|
|
|
|
|
|
|
|
FreeRTOS is free software; you can redistribute it and/or modify it under
|
|
|
|
the terms of the GNU General Public License (version 2) as published by the
|
|
|
|
Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
|
|
|
|
|
|
|
|
***************************************************************************
|
|
|
|
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
|
|
|
>>! distribute a combined work that includes FreeRTOS without being !<<
|
|
|
|
>>! obliged to provide the source code for proprietary components !<<
|
|
|
|
>>! outside of the FreeRTOS kernel. !<<
|
|
|
|
***************************************************************************
|
|
|
|
|
|
|
|
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
|
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
|
|
|
link: http://www.freertos.org/a00114.html
|
|
|
|
|
|
|
|
***************************************************************************
|
|
|
|
* *
|
|
|
|
* FreeRTOS provides completely free yet professionally developed, *
|
|
|
|
* robust, strictly quality controlled, supported, and cross *
|
|
|
|
* platform software that is more than just the market leader, it *
|
|
|
|
* is the industry's de facto standard. *
|
|
|
|
* *
|
|
|
|
* Help yourself get started quickly while simultaneously helping *
|
|
|
|
* to support the FreeRTOS project by purchasing a FreeRTOS *
|
|
|
|
* tutorial book, reference manual, or both: *
|
|
|
|
* http://www.FreeRTOS.org/Documentation *
|
|
|
|
* *
|
|
|
|
***************************************************************************
|
|
|
|
|
|
|
|
http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
|
|
|
|
the FAQ page "My application does not run, what could be wrong?". Have you
|
|
|
|
defined configASSERT()?
|
|
|
|
|
|
|
|
http://www.FreeRTOS.org/support - In return for receiving this top quality
|
|
|
|
embedded software for free we request you assist our global community by
|
|
|
|
participating in the support forum.
|
|
|
|
|
|
|
|
http://www.FreeRTOS.org/training - Investing in training allows your team to
|
|
|
|
be as productive as possible as early as possible. Now you can receive
|
|
|
|
FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
|
|
|
|
Ltd, and the world's leading authority on the world's leading RTOS.
|
|
|
|
|
|
|
|
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
|
|
|
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
|
|
|
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
|
|
|
|
|
|
|
http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
|
|
|
|
Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
|
|
|
|
|
|
|
|
http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
|
|
|
|
Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
|
|
|
|
licenses offer ticketed support, indemnification and commercial middleware.
|
|
|
|
|
|
|
|
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
|
|
|
engineered and independently SIL3 certified version for use in safety and
|
|
|
|
mission critical applications that require provable dependability.
|
|
|
|
|
|
|
|
1 tab == 4 spaces!
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
// Copyright (c) 2003-2015 Cadence Design Systems, Inc.
|
|
|
|
//
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining
|
|
|
|
// a copy of this software and associated documentation files (the
|
|
|
|
// "Software"), to deal in the Software without restriction, including
|
|
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
|
|
// the following conditions:
|
|
|
|
//
|
|
|
|
// The above copyright notice and this permission notice shall be included
|
|
|
|
// in all copies or substantial portions of the Software.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
|
|
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
|
|
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
|
|
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
|
|
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#include <stdlib.h>
|
2018-02-04 22:06:45 +00:00
|
|
|
#include <string.h>
|
2016-08-17 15:08:22 +00:00
|
|
|
#include <xtensa/config/core.h>
|
|
|
|
|
|
|
|
#include "xtensa_rtos.h"
|
|
|
|
|
2017-02-13 03:46:37 +00:00
|
|
|
#include "soc/cpu.h"
|
2016-08-17 15:08:22 +00:00
|
|
|
|
|
|
|
#include "FreeRTOS.h"
|
|
|
|
#include "task.h"
|
|
|
|
|
2019-03-26 08:30:43 +00:00
|
|
|
#include "esp_debug_helpers.h"
|
2017-05-03 08:03:28 +00:00
|
|
|
#include "esp_heap_caps.h"
|
2019-03-15 09:44:27 +00:00
|
|
|
#include "esp_private/crosscore_int.h"
|
2016-10-26 13:09:55 +00:00
|
|
|
|
2017-03-22 03:07:37 +00:00
|
|
|
#include "esp_intr_alloc.h"
|
2018-08-06 01:55:34 +00:00
|
|
|
#include "esp_log.h"
|
2019-06-06 02:57:29 +00:00
|
|
|
#include "sdkconfig.h"
|
2019-10-15 21:01:05 +00:00
|
|
|
#include "esp_compiler.h"
|
2017-03-22 03:07:37 +00:00
|
|
|
|
2020-02-05 14:40:15 +00:00
|
|
|
#include "esp_task_wdt.h"
|
|
|
|
#include "esp_task.h"
|
|
|
|
|
|
|
|
#include "soc/soc_caps.h"
|
|
|
|
#include "soc/efuse_reg.h"
|
|
|
|
#include "soc/dport_access.h"
|
|
|
|
#include "soc/dport_reg.h"
|
|
|
|
#include "esp_int_wdt.h"
|
|
|
|
|
2016-08-17 15:08:22 +00:00
|
|
|
/* Defined in portasm.h */
|
|
|
|
extern void _frxt_tick_timer_init(void);
|
|
|
|
|
|
|
|
/* Defined in xtensa_context.S */
|
|
|
|
extern void _xt_coproc_init(void);
|
|
|
|
|
2020-02-05 14:40:15 +00:00
|
|
|
static const char* TAG = "cpu_start"; // [refactor-todo]: might be appropriate to change in the future, but
|
|
|
|
// for now maintain the same log output
|
2016-08-17 15:08:22 +00:00
|
|
|
|
2017-03-22 03:07:37 +00:00
|
|
|
#if CONFIG_FREERTOS_CORETIMER_0
|
|
|
|
#define SYSTICK_INTR_ID (ETS_INTERNAL_TIMER0_INTR_SOURCE+ETS_INTERNAL_INTR_SOURCE_OFF)
|
|
|
|
#endif
|
|
|
|
#if CONFIG_FREERTOS_CORETIMER_1
|
|
|
|
#define SYSTICK_INTR_ID (ETS_INTERNAL_TIMER1_INTR_SOURCE+ETS_INTERNAL_INTR_SOURCE_OFF)
|
|
|
|
#endif
|
|
|
|
|
2020-02-05 14:40:15 +00:00
|
|
|
|
|
|
|
|
2018-09-17 04:23:09 +00:00
|
|
|
_Static_assert(tskNO_AFFINITY == CONFIG_FREERTOS_NO_AFFINITY, "incorrect tskNO_AFFINITY value");
|
|
|
|
|
2016-08-17 15:08:22 +00:00
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
unsigned port_xSchedulerRunning[portNUM_PROCESSORS] = {0}; // Duplicate of inaccessible xSchedulerRunning; needed at startup to avoid counting nesting
|
2017-02-27 08:34:19 +00:00
|
|
|
unsigned port_interruptNesting[portNUM_PROCESSORS] = {0}; // Interrupt nesting level. Increased/decreased in portasm.c, _frxt_int_enter/_frxt_int_exit
|
2020-01-21 22:20:34 +00:00
|
|
|
BaseType_t port_uxCriticalNesting[portNUM_PROCESSORS] = {0};
|
|
|
|
BaseType_t port_uxOldInterruptState[portNUM_PROCESSORS] = {0};
|
2016-08-17 15:08:22 +00:00
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
|
|
|
|
// User exception dispatcher when exiting
|
|
|
|
void _xt_user_exit(void);
|
|
|
|
|
2018-08-06 01:55:34 +00:00
|
|
|
#if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
|
|
|
|
// Wrapper to allow task functions to return (increases stack overhead by 16 bytes)
|
|
|
|
static void vPortTaskWrapper(TaskFunction_t pxCode, void *pvParameters)
|
|
|
|
{
|
|
|
|
pxCode(pvParameters);
|
|
|
|
//FreeRTOS tasks should not return. Log the task name and abort.
|
|
|
|
char * pcTaskName = pcTaskGetTaskName(NULL);
|
|
|
|
ESP_LOGE("FreeRTOS", "FreeRTOS Task \"%s\" should not return, Aborting now!", pcTaskName);
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-03-22 03:07:37 +00:00
|
|
|
/*
|
2016-08-17 15:08:22 +00:00
|
|
|
* Stack initialization
|
|
|
|
*/
|
|
|
|
#if portUSING_MPU_WRAPPERS
|
|
|
|
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters, BaseType_t xRunPrivileged )
|
|
|
|
#else
|
|
|
|
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
StackType_t *sp, *tp;
|
|
|
|
XtExcFrame *frame;
|
|
|
|
#if XCHAL_CP_NUM > 0
|
|
|
|
uint32_t *p;
|
|
|
|
#endif
|
2018-02-04 22:06:45 +00:00
|
|
|
uint32_t *threadptr;
|
|
|
|
void *task_thread_local_start;
|
|
|
|
extern int _thread_local_start, _thread_local_end, _rodata_start;
|
|
|
|
// TODO: check that TLS area fits the stack
|
|
|
|
uint32_t thread_local_sz = (uint8_t *)&_thread_local_end - (uint8_t *)&_thread_local_start;
|
2016-08-17 15:08:22 +00:00
|
|
|
|
2018-02-04 22:06:45 +00:00
|
|
|
thread_local_sz = ALIGNUP(0x10, thread_local_sz);
|
|
|
|
|
|
|
|
/* Initialize task's stack so that we have the following structure at the top:
|
|
|
|
|
|
|
|
----LOW ADDRESSES ----------------------------------------HIGH ADDRESSES----------
|
|
|
|
task stack | interrupt stack frame | thread local vars | co-processor save area |
|
|
|
|
----------------------------------------------------------------------------------
|
|
|
|
| |
|
|
|
|
SP pxTopOfStack
|
|
|
|
|
|
|
|
All parts are aligned to 16 byte boundary. */
|
|
|
|
sp = (StackType_t *) (((UBaseType_t)(pxTopOfStack + 1) - XT_CP_SIZE - thread_local_sz - XT_STK_FRMSZ) & ~0xf);
|
2016-08-17 15:08:22 +00:00
|
|
|
|
|
|
|
/* Clear the entire frame (do not use memset() because we don't depend on C library) */
|
|
|
|
for (tp = sp; tp <= pxTopOfStack; ++tp)
|
|
|
|
*tp = 0;
|
|
|
|
|
|
|
|
frame = (XtExcFrame *) sp;
|
|
|
|
|
|
|
|
/* Explicitly initialize certain saved registers */
|
2018-08-06 01:55:34 +00:00
|
|
|
#if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
|
|
|
|
frame->pc = (UBaseType_t) vPortTaskWrapper; /* task wrapper */
|
|
|
|
#else
|
|
|
|
frame->pc = (UBaseType_t) pxCode; /* task entrypoint */
|
|
|
|
#endif
|
|
|
|
frame->a0 = 0; /* to terminate GDB backtrace */
|
|
|
|
frame->a1 = (UBaseType_t) sp + XT_STK_FRMSZ; /* physical top of stack frame */
|
|
|
|
frame->exit = (UBaseType_t) _xt_user_exit; /* user exception exit dispatcher */
|
2016-08-17 15:08:22 +00:00
|
|
|
|
|
|
|
/* Set initial PS to int level 0, EXCM disabled ('rfe' will enable), user mode. */
|
|
|
|
/* Also set entry point argument parameter. */
|
|
|
|
#ifdef __XTENSA_CALL0_ABI__
|
2018-08-06 01:55:34 +00:00
|
|
|
#if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
|
|
|
|
frame->a2 = (UBaseType_t) pxCode;
|
|
|
|
frame->a3 = (UBaseType_t) pvParameters;
|
|
|
|
#else
|
|
|
|
frame->a2 = (UBaseType_t) pvParameters;
|
|
|
|
#endif
|
2016-08-17 15:08:22 +00:00
|
|
|
frame->ps = PS_UM | PS_EXCM;
|
|
|
|
#else
|
|
|
|
/* + for windowed ABI also set WOE and CALLINC (pretend task was 'call4'd). */
|
2018-08-06 01:55:34 +00:00
|
|
|
#if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
|
|
|
|
frame->a6 = (UBaseType_t) pxCode;
|
|
|
|
frame->a7 = (UBaseType_t) pvParameters;
|
|
|
|
#else
|
|
|
|
frame->a6 = (UBaseType_t) pvParameters;
|
|
|
|
#endif
|
2016-08-17 15:08:22 +00:00
|
|
|
frame->ps = PS_UM | PS_EXCM | PS_WOE | PS_CALLINC(1);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef XT_USE_SWPRI
|
|
|
|
/* Set the initial virtual priority mask value to all 1's. */
|
|
|
|
frame->vpri = 0xFFFFFFFF;
|
|
|
|
#endif
|
|
|
|
|
2018-02-04 22:06:45 +00:00
|
|
|
/* Init threadptr reg and TLS vars */
|
|
|
|
task_thread_local_start = (void *)(((uint32_t)pxTopOfStack - XT_CP_SIZE - thread_local_sz) & ~0xf);
|
|
|
|
memcpy(task_thread_local_start, &_thread_local_start, thread_local_sz);
|
|
|
|
threadptr = (uint32_t *)(sp + XT_STK_EXTRA);
|
esp32s2: fix THREADPTR calculation, re-enable FreeRTOS TLS tests
1. Clarify THREADPTR calculation in FreeRTOS code, explaining where
the constant 0x10 offset comes from.
2. On the ESP32-S2, .flash.rodata section had different default
alignment (8 bytes instead of 16), which resulted in different offset
of the TLS sections. Unfortunately I haven’t found a way to query
section alignment from C code, or to use a constant value to define
section alignment in the linker script. The linker scripts are
modified to force a fixed 16 byte alignment for .flash.rodata on the
ESP32 and ESP32-S2beta. Note that the base address of .flash.rodata
was already 16 byte aligned, so this has not changed the actual
memory layout of the application.
Full explanation of the calculation below.
Assume we have the TLS template section base address
(tls_section_vma), the address of a TLS variable in the template
(address), and the final relocation value (offset). The linker
calculates:
offset = address - tls_section_vma + align_up(TCB_SIZE, alignment).
At run time, the TLS section gets copied from _thread_local_start
(in .rodata) to task_thread_local_start. Let’s assume that an address
of a variable in the runtime TLS section is runtime_address.
Access to this address will happen by calculating THREADPTR + offset.
So, by a series of substitutions:
THREADPTR + offset = runtime_address THREADPTR = runtime_address - offset
THREADPTR = runtime_address - (address - tls_section_vma + align_up(TCB_SIZE, alignment)) THREADPTR = (runtime_address - address) + tls_section_vma - align_up(TCB_SIZE, alignment)
The difference between runtime_address and address is same as the
difference between task_thread_local_start and _thread_local_start.
And tls_section_vma is the address of .rodata section, i.e.
_rodata_start. So we arrive to
THREADPTR = task_thread_local_start - _thread_local_start + _rodata_start - align_up(TCB_SIZE, alignment).
The idea with TCB_SIZE being added to the THREADPTR when computing
the relocation was to let the OS save TCB pointer in the TREADPTR
register. The location of the run-time TLS section was assumed to be
immediately after the TCB, aligned to whatever the section alignment
was. However in our case the problem is that the run-time TLS section
is stored not next to the TCB, but at the top of the stack. Plus,
even if it was stored next to the TCB, the size of a FreeRTOS TCB is
not equal to 8 bytes (TCB_SIZE hardcoded in the linker). So we have
to calculate THREADPTR in a slightly obscure way, to compensate for
these differences.
Closes IDF-1239
2020-01-20 13:20:02 +00:00
|
|
|
/* Calculate THREADPTR value:
|
|
|
|
* The generated code will add THREADPTR value to a constant value determined at link time,
|
|
|
|
* to get the address of the TLS variable.
|
|
|
|
* The constant value is calculated by the linker as follows
|
|
|
|
* (search for 'tpoff' in elf32-xtensa.c in BFD):
|
|
|
|
* offset = address - tls_section_vma + align_up(TCB_SIZE, tls_section_alignment)
|
|
|
|
* where TCB_SIZE is hardcoded to 8. There doesn't seem to be a way to propagate
|
|
|
|
* the section alignment value from the ld script into the code, so it is hardcoded
|
|
|
|
* in both places.
|
|
|
|
*/
|
|
|
|
const uint32_t tls_section_alignment = 0x10; /* has to be in sync with ALIGN value of .flash.rodata section */
|
|
|
|
const uint32_t tcb_size = 8; /* Unrelated to FreeRTOS, this is the constant from BFD */
|
|
|
|
const uint32_t base = (tcb_size + tls_section_alignment - 1) & (~(tls_section_alignment - 1));
|
|
|
|
*threadptr = (uint32_t)task_thread_local_start - ((uint32_t)&_thread_local_start - (uint32_t)&_rodata_start) - base;
|
2018-02-04 22:06:45 +00:00
|
|
|
|
2016-08-17 15:08:22 +00:00
|
|
|
#if XCHAL_CP_NUM > 0
|
|
|
|
/* Init the coprocessor save area (see xtensa_context.h) */
|
|
|
|
/* No access to TCB here, so derive indirectly. Stack growth is top to bottom.
|
|
|
|
* //p = (uint32_t *) xMPUSettings->coproc_area;
|
|
|
|
*/
|
|
|
|
p = (uint32_t *)(((uint32_t) pxTopOfStack - XT_CP_SIZE) & ~0xf);
|
|
|
|
p[0] = 0;
|
|
|
|
p[1] = 0;
|
|
|
|
p[2] = (((uint32_t) p) + 12 + XCHAL_TOTAL_SA_ALIGN - 1) & -XCHAL_TOTAL_SA_ALIGN;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return sp;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
|
|
|
|
void vPortEndScheduler( void )
|
|
|
|
{
|
|
|
|
/* It is unlikely that the Xtensa port will get stopped. If required simply
|
|
|
|
disable the tick interrupt here. */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
|
|
|
|
BaseType_t xPortStartScheduler( void )
|
|
|
|
{
|
|
|
|
// Interrupts are disabled at this point and stack contains PS with enabled interrupts when task context is restored
|
|
|
|
|
|
|
|
#if XCHAL_CP_NUM > 0
|
|
|
|
/* Initialize co-processor management for tasks. Leave CPENABLE alone. */
|
|
|
|
_xt_coproc_init();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Init the tick divisor value */
|
|
|
|
_xt_tick_divisor_init();
|
|
|
|
|
|
|
|
/* Setup the hardware to generate the tick. */
|
|
|
|
_frxt_tick_timer_init();
|
|
|
|
|
|
|
|
port_xSchedulerRunning[xPortGetCoreID()] = 1;
|
|
|
|
|
|
|
|
// Cannot be directly called from C; never returns
|
|
|
|
__asm__ volatile ("call0 _frxt_dispatch\n");
|
|
|
|
|
|
|
|
/* Should not get here. */
|
|
|
|
return pdTRUE;
|
|
|
|
}
|
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
|
|
|
|
BaseType_t xPortSysTickHandler( void )
|
|
|
|
{
|
|
|
|
BaseType_t ret;
|
|
|
|
|
|
|
|
portbenchmarkIntLatency();
|
2017-03-22 03:07:37 +00:00
|
|
|
traceISR_ENTER(SYSTICK_INTR_ID);
|
2016-08-17 15:08:22 +00:00
|
|
|
ret = xTaskIncrementTick();
|
|
|
|
if( ret != pdFALSE )
|
|
|
|
{
|
|
|
|
portYIELD_FROM_ISR();
|
2017-03-22 03:07:37 +00:00
|
|
|
} else {
|
|
|
|
traceISR_EXIT();
|
2016-08-17 15:08:22 +00:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
2016-10-26 13:09:55 +00:00
|
|
|
|
|
|
|
|
|
|
|
void vPortYieldOtherCore( BaseType_t coreid ) {
|
|
|
|
esp_crosscore_int_send_yield( coreid );
|
|
|
|
}
|
|
|
|
|
2016-08-17 15:08:22 +00:00
|
|
|
/*-----------------------------------------------------------*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Used to set coprocessor area in stack. Current hack is to reuse MPU pointer for coprocessor area.
|
|
|
|
*/
|
|
|
|
#if portUSING_MPU_WRAPPERS
|
2017-04-19 02:47:19 +00:00
|
|
|
void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMORY_REGION * const xRegions, StackType_t *pxBottomOfStack, uint32_t usStackDepth )
|
2016-08-17 15:08:22 +00:00
|
|
|
{
|
|
|
|
#if XCHAL_CP_NUM > 0
|
|
|
|
xMPUSettings->coproc_area = (StackType_t*)((((uint32_t)(pxBottomOfStack + usStackDepth - 1)) - XT_CP_SIZE ) & ~0xf);
|
|
|
|
|
|
|
|
|
|
|
|
/* NOTE: we cannot initialize the coprocessor save area here because FreeRTOS is going to
|
|
|
|
* clear the stack area after we return. This is done in pxPortInitialiseStack().
|
|
|
|
*/
|
|
|
|
#endif
|
|
|
|
}
|
2017-05-31 09:20:29 +00:00
|
|
|
|
|
|
|
void vPortReleaseTaskMPUSettings( xMPU_SETTINGS *xMPUSettings )
|
|
|
|
{
|
|
|
|
/* If task has live floating point registers somewhere, release them */
|
|
|
|
_xt_coproc_release( xMPUSettings->coproc_area );
|
|
|
|
}
|
|
|
|
|
2016-08-17 15:08:22 +00:00
|
|
|
#endif
|
|
|
|
|
2017-02-27 08:34:19 +00:00
|
|
|
/*
|
|
|
|
* Returns true if the current core is in ISR context; low prio ISR, med prio ISR or timer tick ISR. High prio ISRs
|
|
|
|
* aren't detected here, but they normally cannot call C code, so that should not be an issue anyway.
|
|
|
|
*/
|
2019-07-16 09:33:30 +00:00
|
|
|
BaseType_t xPortInIsrContext(void)
|
2017-02-27 08:34:19 +00:00
|
|
|
{
|
|
|
|
unsigned int irqStatus;
|
|
|
|
BaseType_t ret;
|
|
|
|
irqStatus=portENTER_CRITICAL_NESTED();
|
|
|
|
ret=(port_interruptNesting[xPortGetCoreID()] != 0);
|
|
|
|
portEXIT_CRITICAL_NESTED(irqStatus);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-01-11 13:43:58 +00:00
|
|
|
/*
|
|
|
|
* This function will be called in High prio ISRs. Returns true if the current core was in ISR context
|
|
|
|
* before calling into high prio ISR context.
|
|
|
|
*/
|
2019-07-16 09:33:30 +00:00
|
|
|
BaseType_t IRAM_ATTR xPortInterruptedFromISRContext(void)
|
2018-01-11 13:43:58 +00:00
|
|
|
{
|
|
|
|
return (port_interruptNesting[xPortGetCoreID()] != 0);
|
|
|
|
}
|
2017-02-27 08:34:19 +00:00
|
|
|
|
2019-07-16 09:33:30 +00:00
|
|
|
void vPortAssertIfInISR(void)
|
2016-09-05 04:30:57 +00:00
|
|
|
{
|
2017-02-27 08:34:19 +00:00
|
|
|
configASSERT(xPortInIsrContext());
|
2016-09-05 04:30:57 +00:00
|
|
|
}
|
|
|
|
|
2017-01-10 05:05:19 +00:00
|
|
|
void vPortSetStackWatchpoint( void* pxStackStart ) {
|
|
|
|
//Set watchpoint 1 to watch the last 32 bytes of the stack.
|
|
|
|
//Unfortunately, the Xtensa watchpoints can't set a watchpoint on a random [base - base+n] region because
|
|
|
|
//the size works by masking off the lowest address bits. For that reason, we futz a bit and watch the lowest 32
|
|
|
|
//bytes of the stack we can actually watch. In general, this can cause the watchpoint to be triggered at most
|
|
|
|
//28 bytes early. The value 32 is chosen because it's larger than the stack canary, which in FreeRTOS is 20 bytes.
|
|
|
|
//This way, we make sure we trigger before/when the stack canary is corrupted, not after.
|
|
|
|
int addr=(int)pxStackStart;
|
|
|
|
addr=(addr+31)&(~31);
|
|
|
|
esp_set_watchpoint(1, (char*)addr, 32, ESP_WATCHPOINT_STORE);
|
|
|
|
}
|
|
|
|
|
2020-01-21 22:20:34 +00:00
|
|
|
uint32_t xPortGetTickRateHz(void) {
|
|
|
|
return (uint32_t)configTICK_RATE_HZ;
|
|
|
|
}
|
2020-01-07 13:46:59 +00:00
|
|
|
|
2020-01-21 22:20:34 +00:00
|
|
|
void __attribute__((optimize("-O3"))) vPortEnterCritical(portMUX_TYPE *mux)
|
|
|
|
{
|
|
|
|
BaseType_t oldInterruptLevel = portENTER_CRITICAL_NESTED();
|
|
|
|
/* Interrupts may already be disabled (because we're doing this recursively)
|
|
|
|
* but we can't get the interrupt level after
|
|
|
|
* vPortCPUAquireMutex, because it also may mess with interrupts.
|
|
|
|
* Get it here first, then later figure out if we're nesting
|
|
|
|
* and save for real there.
|
|
|
|
*/
|
|
|
|
vPortCPUAcquireMutex( mux );
|
|
|
|
BaseType_t coreID = xPortGetCoreID();
|
|
|
|
BaseType_t newNesting = port_uxCriticalNesting[coreID] + 1;
|
|
|
|
port_uxCriticalNesting[coreID] = newNesting;
|
|
|
|
|
|
|
|
if( newNesting == 1 )
|
|
|
|
{
|
|
|
|
//This is the first time we get called. Save original interrupt level.
|
|
|
|
port_uxOldInterruptState[coreID] = oldInterruptLevel;
|
2017-12-19 07:47:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-21 22:20:34 +00:00
|
|
|
void __attribute__((optimize("-O3"))) vPortExitCritical(portMUX_TYPE *mux)
|
|
|
|
{
|
|
|
|
vPortCPUReleaseMutex( mux );
|
|
|
|
BaseType_t coreID = xPortGetCoreID();
|
|
|
|
BaseType_t nesting = port_uxCriticalNesting[coreID];
|
|
|
|
|
|
|
|
if(nesting > 0U)
|
|
|
|
{
|
|
|
|
nesting--;
|
|
|
|
port_uxCriticalNesting[coreID] = nesting;
|
2017-12-19 07:47:00 +00:00
|
|
|
|
2020-01-21 22:20:34 +00:00
|
|
|
if( nesting == 0U )
|
|
|
|
{
|
|
|
|
portEXIT_CRITICAL_NESTED(port_uxOldInterruptState[coreID]);
|
|
|
|
}
|
|
|
|
}
|
2017-02-16 11:05:07 +00:00
|
|
|
}
|
2020-02-02 15:23:16 +00:00
|
|
|
|
|
|
|
void __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName )
|
|
|
|
{
|
|
|
|
#define ERR_STR1 "***ERROR*** A stack overflow in task "
|
|
|
|
#define ERR_STR2 " has been detected."
|
|
|
|
const char *str[] = {ERR_STR1, pcTaskName, ERR_STR2};
|
|
|
|
|
|
|
|
char buf[sizeof(ERR_STR1) + CONFIG_FREERTOS_MAX_TASK_NAME_LEN + sizeof(ERR_STR2) + 1 /* null char */] = { 0 };
|
|
|
|
|
|
|
|
char *dest = buf;
|
|
|
|
for (int i = 0 ; i < sizeof(str)/ sizeof(str[0]); i++) {
|
|
|
|
dest = strcat(dest, str[i]);
|
|
|
|
}
|
|
|
|
esp_system_abort(buf);
|
2020-02-05 14:40:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// `esp_system` calls the app entry point app_main for core 0 and app_mainX for
|
|
|
|
// the rest of the cores which the app normally provides for non-os builds.
|
|
|
|
// If `freertos` is included in the build, wrap the call to app_main and provide
|
|
|
|
// our own definition of app_mainX so that we can do our own initializations for each
|
|
|
|
// core and start the scheduler.
|
|
|
|
//
|
|
|
|
// We now simply execute the real app_main in the context of the main task that
|
|
|
|
// we also start.
|
|
|
|
extern void __real_app_main(void);
|
|
|
|
|
|
|
|
static void main_task(void* args)
|
|
|
|
{
|
|
|
|
#if !CONFIG_FREERTOS_UNICORE
|
|
|
|
// Wait for FreeRTOS initialization to finish on APP CPU, before replacing its startup stack
|
|
|
|
while (port_xSchedulerRunning[1] == 0) {
|
|
|
|
;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//Initialize task wdt if configured to do so
|
|
|
|
#ifdef CONFIG_ESP_TASK_WDT_PANIC
|
|
|
|
ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, true));
|
|
|
|
#elif CONFIG_ESP_TASK_WDT
|
|
|
|
ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, false));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//Add IDLE 0 to task wdt
|
|
|
|
#ifdef CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0
|
|
|
|
TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0);
|
|
|
|
if(idle_0 != NULL){
|
|
|
|
ESP_ERROR_CHECK(esp_task_wdt_add(idle_0));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
//Add IDLE 1 to task wdt
|
|
|
|
#ifdef CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1
|
|
|
|
TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCPU(1);
|
|
|
|
if(idle_1 != NULL){
|
|
|
|
ESP_ERROR_CHECK(esp_task_wdt_add(idle_1));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
__real_app_main();
|
|
|
|
vTaskDelete(NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if !CONFIG_FREERTOS_UNICORE
|
|
|
|
void app_mainX(void)
|
|
|
|
{
|
|
|
|
if (xPortGetCoreID() >= 2) {
|
|
|
|
// Explicitly support only up to two cores for now.
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wait for FreeRTOS initialization to finish on PRO CPU
|
|
|
|
while (port_xSchedulerRunning[0] == 0) {
|
|
|
|
;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if CONFIG_ESP_INT_WDT
|
|
|
|
//Initialize the interrupt watch dog for CPU1.
|
|
|
|
esp_int_wdt_cpu_init();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
esp_crosscore_int_init();
|
|
|
|
esp_dport_access_int_init();
|
|
|
|
|
|
|
|
ESP_EARLY_LOGI(TAG, "Starting scheduler on APP CPU.");
|
|
|
|
xPortStartScheduler();
|
|
|
|
abort(); /* Only get to here if FreeRTOS somehow very broken */
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void __wrap_app_main(void)
|
|
|
|
{
|
|
|
|
#if CONFIG_ESP_INT_WDT
|
|
|
|
esp_int_wdt_init();
|
|
|
|
//Initialize the interrupt watch dog for CPU0.
|
|
|
|
esp_int_wdt_cpu_init();
|
|
|
|
#else
|
|
|
|
#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
|
|
|
|
assert(!soc_has_cache_lock_bug() && "ESP32 Rev 3 + Dual Core + PSRAM requires INT WDT enabled in project config!");
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
esp_crosscore_int_init();
|
|
|
|
|
|
|
|
#ifndef CONFIG_FREERTOS_UNICORE
|
|
|
|
esp_dport_access_int_init();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, "main",
|
|
|
|
ESP_TASK_MAIN_STACK, NULL,
|
|
|
|
ESP_TASK_MAIN_PRIO, NULL, 0);
|
|
|
|
assert(res == pdTRUE);
|
|
|
|
|
|
|
|
#if !CONFIG_FREERTOS_UNICORE
|
|
|
|
// Check that FreeRTOS is configured properly for the number of cores the target
|
|
|
|
// has at compile and build time.
|
|
|
|
#if SOC_CPU_CORES_NUM < 2
|
|
|
|
#error FreeRTOS configured to run on dual core, but target only has a single core.
|
|
|
|
#endif
|
|
|
|
if (REG_GET_BIT(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_DIS_APP_CPU)) {
|
|
|
|
ESP_EARLY_LOGE(TAG, "Running on single core chip, but application is built with dual core support.");
|
|
|
|
ESP_EARLY_LOGE(TAG, "Please enable CONFIG_FREERTOS_UNICORE option in menuconfig.");
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
#if SOC_CPU_CORES_NUM > 1 // Single core chips have no 'single core mode'
|
|
|
|
ESP_EARLY_LOGI(TAG, "Single core mode");
|
|
|
|
DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN);
|
|
|
|
#endif
|
|
|
|
#endif // !CONFIG_FREERTOS_UNICORE
|
|
|
|
|
|
|
|
ESP_LOGI(TAG, "Starting scheduler on PRO CPU.");
|
|
|
|
vTaskStartScheduler();
|
2020-02-02 15:23:16 +00:00
|
|
|
}
|