Updated ESP32 port-layer to ESP-IDF v4.4.2 (#572)

* Xtensa_ESP32: Added esp-idf v4.4.2 specific changes

* Xtensa_ESP32: Updated SPDX license identifiers
This commit is contained in:
Laukik Hase 2022-10-12 02:57:32 +05:30 committed by GitHub
parent 195a351ec7
commit 963abe6c48
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 854 additions and 1096 deletions

View File

@ -0,0 +1,134 @@
/*
* SPDX-FileCopyrightText: 2022 Amazon.com, Inc. or its affiliates
*
* SPDX-License-Identifier: MIT
*
* SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD
*/
/*
* FreeRTOS Kernel V10.4.3
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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. If you wish to use our Amazon
* FreeRTOS name, please do so in a fair use way that does not cause confusion.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
* 1 tab == 4 spaces!
*/
#ifndef FREERTOS_CONFIG_XTENSA_H
#define FREERTOS_CONFIG_XTENSA_H
#include "sdkconfig.h"
/* enable use of optimized task selection by the scheduler */
#if defined (CONFIG_FREERTOS_OPTIMIZED_SCHEDULER) && !defined(configUSE_PORT_OPTIMISED_TASK_SELECTION)
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1
#endif
#define XT_USE_THREAD_SAFE_CLIB 0
#undef XT_USE_SWPRI
#if CONFIG_FREERTOS_CORETIMER_0
#define XT_TIMER_INDEX 0
#elif CONFIG_FREERTOS_CORETIMER_1
#define XT_TIMER_INDEX 1
#endif
#ifndef __ASSEMBLER__
/**
* This function is defined to provide a deprecation warning whenever
* XT_CLOCK_FREQ macro is used.
* Update the code to use esp_clk_cpu_freq function instead.
* @return current CPU clock frequency, in Hz
*/
int xt_clock_freq(void) __attribute__((deprecated));
#define XT_CLOCK_FREQ (xt_clock_freq())
#endif // __ASSEMBLER__
/* Required for configuration-dependent settings */
#include <xtensa_config.h>
/* configASSERT behaviour */
#ifndef __ASSEMBLER__
#include <assert.h>
#include "esp_rom_sys.h"
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/rom/ets_sys.h" // will be removed in idf v5.0
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/ets_sys.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/rom/ets_sys.h"
#endif
#endif // __ASSEMBLER__
// If CONFIG_FREERTOS_ASSERT_DISABLE is set then configASSERT is defined empty later in FreeRTOS.h and the macro
// configASSERT_DEFINED remains unset (meaning some warnings are avoided)
#ifdef configASSERT
#undef configASSERT
#if defined(CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE)
#define configASSERT(a) if (unlikely(!(a))) { \
esp_rom_printf("%s:%d (%s)- assert failed!\n", __FILE__, __LINE__, \
__FUNCTION__); \
}
#elif defined(CONFIG_FREERTOS_ASSERT_FAIL_ABORT)
#define configASSERT(a) assert(a)
#endif
#endif
#if CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION
#define UNTESTED_FUNCTION() { esp_rom_printf("Untested FreeRTOS function %s\r\n", __FUNCTION__); configASSERT(false); } while(0)
#else
#define UNTESTED_FUNCTION()
#endif
#define configXT_BOARD 1 /* Board mode */
#define configXT_SIMULATOR 0
/* The maximum interrupt priority from which FreeRTOS.org API functions can
be called. Only API functions that end in ...FromISR() can be used within
interrupts. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY XCHAL_EXCM_LEVEL
/* Stack alignment, architecture specifc. Must be a power of two. */
#define configSTACK_ALIGNMENT 16
/* The Xtensa port uses a separate interrupt stack. Adjust the stack size
* to suit the needs of your specific application.
* Size needs to be aligned to the stack increment, since the location of
* the stack for the 2nd CPU will be calculated using configISR_STACK_SIZE.
*/
#ifndef configISR_STACK_SIZE
#define configISR_STACK_SIZE ((CONFIG_FREERTOS_ISR_STACKSIZE + configSTACK_ALIGNMENT - 1) & (~(configSTACK_ALIGNMENT - 1)))
#endif
#ifndef __ASSEMBLER__
#if CONFIG_APPTRACE_SV_ENABLE
extern uint32_t port_switch_flag[];
#define os_task_switch_is_pended(_cpu_) (port_switch_flag[_cpu_])
#else
#define os_task_switch_is_pended(_cpu_) (false)
#endif
#endif
#endif // FREERTOS_CONFIG_XTENSA_H

View File

@ -0,0 +1,20 @@
/*
* SPDX-FileCopyrightText: 2017-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Set up the SysTick interrupt
*/
void vPortSetupTimer(void);
#ifdef __cplusplus
}
#endif

View File

@ -74,12 +74,20 @@
#include <xtensa/config/core.h>
#include <xtensa/config/system.h> /* required for XSHAL_CLIB */
#include <xtensa/xtruntime.h>
#include "soc/spinlock.h"
#include "esp_timer.h" /* required for FreeRTOS run time stats */
#include "esp_system.h"
#include "esp_idf_version.h"
#include "esp_heap_caps.h"
/* TODO: Resolve build warnings generated due to this header inclusion */
#include "hal/cpu_hal.h"
#include <esp_heap_caps.h>
/* TODO: These includes are not directly used in this file. They are kept into to prevent a breaking change. Remove these. */
#include <limits.h>
#include <xtensa/xtensa_api.h>
#include "soc/cpu.h"
#include "soc/soc_memory_layout.h"
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0))
#include "soc/compare_set.h"
@ -127,54 +135,12 @@
#include "esp_attr.h"
/* "mux" data structure (spinlock) */
typedef struct
{
/* owner field values:
* 0 - Uninitialized (invalid)
* portMUX_FREE_VAL - Mux is free, can be locked by either CPU
* CORE_ID_REGVAL_PRO / CORE_ID_REGVAL_APP - Mux is locked to the particular core
*
* Any value other than portMUX_FREE_VAL, CORE_ID_REGVAL_PRO, CORE_ID_REGVAL_APP indicates corruption
*/
uint32_t owner;
/* count field:
* If mux is unlocked, count should be zero.
* If mux is locked, count is non-zero & represents the number of recursive locks on the mux.
*/
uint32_t count;
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
const char * lastLockedFn;
int lastLockedLine;
#endif
} portMUX_TYPE;
#define portMUX_FREE_VAL 0xB33FFFFF
/* Special constants for vPortCPUAcquireMutexTimeout() */
#define portMUX_NO_TIMEOUT ( -1 ) /* When passed for 'timeout_cycles', spin forever if necessary */
#define portMUX_TRY_LOCK 0 /* Try to acquire the spinlock a single time only */
/* Keep this in sync with the portMUX_TYPE struct definition please. */
#ifndef CONFIG_FREERTOS_PORTMUX_DEBUG
#define portMUX_INITIALIZER_UNLOCKED \
{ \
.owner = portMUX_FREE_VAL, \
.count = 0, \
}
#else
#define portMUX_INITIALIZER_UNLOCKED \
{ \
.owner = portMUX_FREE_VAL, \
.count = 0, \
.lastLockedFn = "(never locked)", \
.lastLockedLine = -1 \
}
#endif /* ifndef CONFIG_FREERTOS_PORTMUX_DEBUG */
#define portASSERT_IF_IN_ISR() vPortAssertIfInISR()
void vPortAssertIfInISR();
typedef spinlock_t portMUX_TYPE; /**< Spinlock type used by FreeRTOS critical sections */
#define portMUX_INITIALIZER_UNLOCKED SPINLOCK_INITIALIZER /**< Spinlock initializer */
#define portMUX_FREE_VAL SPINLOCK_FREE /**< Spinlock is free. [refactor-todo] check if this is still required */
#define portMUX_NO_TIMEOUT SPINLOCK_WAIT_FOREVER /**< When passed for 'timeout_cycles', spin forever if necessary. [refactor-todo] check if this is still required */
#define portMUX_TRY_LOCK SPINLOCK_NO_WAIT /**< Try to acquire the spinlock a single time only. [refactor-todo] check if this is still required */
#define portMUX_INITIALIZE(mux) spinlock_initialize(mux) /*< Initialize a spinlock to its unlocked state */
#define portCRITICAL_NESTING_IN_TCB 1
@ -200,7 +166,7 @@
* This all assumes that interrupts are either entirely disabled or enabled. Interrupt priority levels
* will break this scheme.
*
* Remark: For the ESP32, portENTER_CRITICAL and portENTER_CRITICAL_ISR both alias vTaskEnterCritical, meaning
* Remark: For the ESP32, portENTER_CRITICAL and portENTER_CRITICAL_ISR both alias vPortEnterCritical, meaning
* that either function can be called both from ISR as well as task context. This is not standard FreeRTOS
* behaviour; please keep this in mind if you need any compatibility with other FreeRTOS implementations.
*/
@ -255,6 +221,8 @@
} \
} while( 0 )
#define portASSERT_IF_IN_ISR() vPortAssertIfInISR()
void vPortAssertIfInISR(void);
/* Critical section management. NW-TODO: replace XTOS_SET_INTLEVEL with more efficient version, if any? */
/* These cannot be nested. They should be used with a lot of care and cannot be called from interrupt level. */
@ -266,18 +234,22 @@
/* Cleaner solution allows nested interrupts disabling and restoring via local registers or stack. */
/* They can be called from interrupts too. */
/* WARNING: Only applies to current CPU. See notes above. */
static inline unsigned portENTER_CRITICAL_NESTED()
static inline UBaseType_t __attribute__( ( always_inline ) ) xPortSetInterruptMaskFromISR( void )
{
unsigned state = XTOS_SET_INTLEVEL( XCHAL_EXCM_LEVEL );
UBaseType_t prev_int_level = XTOS_SET_INTLEVEL( XCHAL_EXCM_LEVEL );
portbenchmarkINTERRUPT_DISABLE();
return state;
return prev_int_level;
}
static inline void __attribute__( ( always_inline ) ) vPortClearInterruptMaskFromISR( UBaseType_t prev_level )
{
portbenchmarkINTERRUPT_RESTORE( prev_level );
XTOS_RESTORE_JUST_INTLEVEL( prev_level );
}
#define portEXIT_CRITICAL_NESTED( state ) do { portbenchmarkINTERRUPT_RESTORE( state ); XTOS_RESTORE_JUST_INTLEVEL( state ); } while( 0 )
/* These FreeRTOS versions are similar to the nested versions above */
#define portSET_INTERRUPT_MASK_FROM_ISR() portENTER_CRITICAL_NESTED()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( state ) portEXIT_CRITICAL_NESTED( state )
#define portSET_INTERRUPT_MASK_FROM_ISR() xPortSetInterruptMaskFromISR()
#define portCLEAR_INTERRUPT_MASK_FROM_ISR( prev_level ) vPortClearInterruptMaskFromISR( prev_level )
/*Because the ROM routines don't necessarily handle a stack in external RAM correctly, we force */
/*the stack memory to always be internal. */
@ -352,7 +324,7 @@
#else
static inline void uxPortCompareSetExtram(volatile uint32_t *addr, uint32_t compare, uint32_t *set)
{
#if defined(CONFIG_ESP32_SPIRAM_SUPPORT)
#if defined(CONFIG_SPIRAM)
compare_and_set_extram(addr, compare, set);
#endif
}
@ -374,18 +346,47 @@
#ifdef CONFIG_FREERTOS_RUN_TIME_STATS_USING_ESP_TIMER
/* Coarse resolution time (us) */
#define portALT_GET_RUN_TIME_COUNTER_VALUE( x ) x = ( uint32_t ) esp_timer_get_time()
#define portALT_GET_RUN_TIME_COUNTER_VALUE( x ) do { x = ( uint32_t )esp_timer_get_time(); } while( 0 )
#endif
/* Kernel utilities. */
void vPortYield( void );
void vPortEvaluateYieldFromISR( int argc, ... );
void _frxt_setup_switch( void );
#define portYIELD() vPortYield()
#define portYIELD_FROM_ISR() { traceISR_EXIT_TO_SCHEDULER(); _frxt_setup_switch(); }
/* Macro to count number of arguments of a __VA_ARGS__ used to support portYIELD_FROM_ISR with,
* or without arguments. The macro counts only 0 or 1 arguments.
*
* In the future, we want to switch to C++20. We also want to become compatible with clang.
* Hence, we provide two versions of the following macros which are using variadic arguments.
* The first one is using the GNU extension ##__VA_ARGS__. The second one is using the C++20 feature __VA_OPT__(,).
* This allows users to compile their code with standard C++20 enabled instead of the GNU extension.
* Below C++20, we haven't found any good alternative to using ##__VA_ARGS__.
*/
#if defined( __cplusplus ) && ( __cplusplus > 201703L )
#define portGET_ARGUMENT_COUNT(...) portGET_ARGUMENT_COUNT_INNER( 0 __VA_OPT__(,) __VA_ARGS__, 1 , 0 )
#else
#define portGET_ARGUMENT_COUNT(...) portGET_ARGUMENT_COUNT_INNER( 0, ##__VA_ARGS__, 1, 0 )
#endif
#define portGET_ARGUMENT_COUNT_INNER( zero, one, count, ... ) count
static inline uint32_t xPortGetCoreID();
_Static_assert( portGET_ARGUMENT_COUNT() == 0, "portGET_ARGUMENT_COUNT() result does not match for 0 arguments" );
_Static_assert( portGET_ARGUMENT_COUNT( 1 ) == 1, "portGET_ARGUMENT_COUNT() result does not match for 1 argument" );
#define portYIELD() vPortYield()
/* The macro below could be used when passing a single argument, or without any argument,
* it was developed to support both usages of portYIELD inside of an ISR. Any other usage form
* might result in undesired behaviour
*/
#if defined( __cplusplus ) && ( __cplusplus > 201703L )
#define portYIELD_FROM_ISR(...) vPortEvaluateYieldFromISR( portGET_ARGUMENT_COUNT( __VA_ARGS__ ) __VA_OPT__( , ) __VA_ARGS__ )
#else
#define portYIELD_FROM_ISR(...) vPortEvaluateYieldFromISR( portGET_ARGUMENT_COUNT( __VA_ARGS__ ), ##__VA_ARGS__ )
#endif
static inline BaseType_t xPortGetCoreID();
/*-----------------------------------------------------------*/
@ -428,10 +429,11 @@
#endif
void vApplicationSleep( TickType_t xExpectedIdleTime );
void vPortSetStackWatchpoint( void* pxStackStart );
#define portSUPPRESS_TICKS_AND_SLEEP( idleTime ) vApplicationSleep( idleTime )
void _xt_coproc_release( volatile void * coproc_sa_base );
/*-----------------------------------------------------------*/
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0))
@ -458,10 +460,6 @@
/*-----------------------------------------------------------*/
void _xt_coproc_release( volatile void * coproc_sa_base );
/*
* Map to the memory management routines required for the port.
*
@ -520,20 +518,31 @@
#endif
/* Multi-core: get current core ID */
static inline uint32_t IRAM_ATTR xPortGetCoreID()
static inline BaseType_t IRAM_ATTR xPortGetCoreID()
{
int id;
asm (
"rsr.prid %0\n"
" extui %0,%0,13,1"
: "=r" ( id ) );
return id;
return ( uint32_t )cpu_hal_get_core_id();
}
/* Get tick rate per second */
uint32_t xPortGetTickRateHz( void );
static inline bool IRAM_ATTR xPortCanYield(void)
{
uint32_t ps_reg = 0;
//Get the current value of PS (processor status) register
RSR(PS, ps_reg);
/*
* intlevel = (ps_reg & 0xf);
* excm = (ps_reg >> 4) & 0x1;
* CINTLEVEL is max(excm * EXCMLEVEL, INTLEVEL), where EXCMLEVEL is 3.
* However, just return true, only intlevel is zero.
*/
return ((ps_reg & PS_INTLEVEL_MASK) == 0);
}
/* porttrace */
#if configUSE_TRACE_FACILITY_2
#include "porttrace.h"

View File

@ -27,113 +27,4 @@
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/******************************************************************************
* Xtensa-specific API for RTOS ports.
******************************************************************************/
#ifndef __XTENSA_API_H__
#define __XTENSA_API_H__
#include <xtensa/hal.h>
#include "xtensa_context.h"
/* Typedef for C-callable interrupt handler function */
typedef void (* xt_handler)( void * );
/* Typedef for C-callable exception handler function */
typedef void (* xt_exc_handler)( XtExcFrame * );
/*
* -------------------------------------------------------------------------------
* Call this function to set a handler for the specified exception. The handler
* will be installed on the core that calls this function.
*
* n - Exception number (type)
* f - Handler function address, NULL to uninstall handler.
*
* The handler will be passed a pointer to the exception frame, which is created
* on the stack of the thread that caused the exception.
*
* If the handler returns, the thread context will be restored and the faulting
* instruction will be retried. Any values in the exception frame that are
* modified by the handler will be restored as part of the context. For details
* of the exception frame structure see xtensa_context.h.
* -------------------------------------------------------------------------------
*/
extern xt_exc_handler xt_set_exception_handler( int n,
xt_exc_handler f );
/*
* -------------------------------------------------------------------------------
* Call this function to set a handler for the specified interrupt. The handler
* will be installed on the core that calls this function.
*
* n - Interrupt number.
* f - Handler function address, NULL to uninstall handler.
* arg - Argument to be passed to handler.
* -------------------------------------------------------------------------------
*/
extern xt_handler xt_set_interrupt_handler( int n,
xt_handler f,
void * arg );
/*
* -------------------------------------------------------------------------------
* Call this function to enable the specified interrupts on the core that runs
* this code.
*
* mask - Bit mask of interrupts to be enabled.
* -------------------------------------------------------------------------------
*/
extern void xt_ints_on( unsigned int mask );
/*
* -------------------------------------------------------------------------------
* Call this function to disable the specified interrupts on the core that runs
* this code.
*
* mask - Bit mask of interrupts to be disabled.
* -------------------------------------------------------------------------------
*/
extern void xt_ints_off( unsigned int mask );
/*
* -------------------------------------------------------------------------------
* Call this function to set the specified (s/w) interrupt.
* -------------------------------------------------------------------------------
*/
static inline void xt_set_intset( unsigned int arg )
{
xthal_set_intset( arg );
}
/*
* -------------------------------------------------------------------------------
* Call this function to clear the specified (s/w or edge-triggered)
* interrupt.
* -------------------------------------------------------------------------------
*/
static inline void xt_set_intclear( unsigned int arg )
{
xthal_set_intclear( arg );
}
/*
* -------------------------------------------------------------------------------
* Call this function to get handler's argument for the specified interrupt.
*
* n - Interrupt number.
* -------------------------------------------------------------------------------
*/
extern void * xt_get_interrupt_handler_arg( int n );
#endif /* __XTENSA_API_H__ */
#include <xtensa/xtensa_api.h>

View File

@ -27,373 +27,4 @@
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*******************************************************************************
XTENSA CONTEXT FRAMES AND MACROS FOR RTOS ASSEMBLER SOURCES
This header contains definitions and macros for use primarily by Xtensa
RTOS assembly coded source files. It includes and uses the Xtensa hardware
abstraction layer (HAL) to deal with config specifics. It may also be
included in C source files.
!! Supports only Xtensa Exception Architecture 2 (XEA2). XEA1 not supported. !!
NOTE: The Xtensa architecture requires stack pointer alignment to 16 bytes.
*******************************************************************************/
#ifndef XTENSA_CONTEXT_H
#define XTENSA_CONTEXT_H
#ifdef __ASSEMBLER__
#include <xtensa/coreasm.h>
#endif
#include <xtensa/config/tie.h>
#include <xtensa/corebits.h>
#include <xtensa/config/system.h>
#include <xtensa/xtruntime-frames.h>
#include <esp_idf_version.h>
/* Align a value up to nearest n-byte boundary, where n is a power of 2. */
#define ALIGNUP(n, val) (((val) + (n)-1) & -(n))
/*
-------------------------------------------------------------------------------
Macros that help define structures for both C and assembler.
-------------------------------------------------------------------------------
*/
#ifdef STRUCT_BEGIN
#undef STRUCT_BEGIN
#undef STRUCT_FIELD
#undef STRUCT_AFIELD
#undef STRUCT_END
#endif
#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__)
#define STRUCT_BEGIN .pushsection .text; .struct 0
#define STRUCT_FIELD(ctype,size,asname,name) asname: .space size
#define STRUCT_AFIELD(ctype,size,asname,name,n) asname: .space (size)*(n)
#define STRUCT_END(sname) sname##Size:; .popsection
#else
#define STRUCT_BEGIN typedef struct {
#define STRUCT_FIELD(ctype,size,asname,name) ctype name;
#define STRUCT_AFIELD(ctype,size,asname,name,n) ctype name[n];
#define STRUCT_END(sname) } sname;
#endif //_ASMLANGUAGE || __ASSEMBLER__
/*
-------------------------------------------------------------------------------
INTERRUPT/EXCEPTION STACK FRAME FOR A THREAD OR NESTED INTERRUPT
A stack frame of this structure is allocated for any interrupt or exception.
It goes on the current stack. If the RTOS has a system stack for handling
interrupts, every thread stack must allow space for just one interrupt stack
frame, then nested interrupt stack frames go on the system stack.
The frame includes basic registers (explicit) and "extra" registers introduced
by user TIE or the use of the MAC16 option in the user's Xtensa config.
The frame size is minimized by omitting regs not applicable to user's config.
For Windowed ABI, this stack frame includes the interruptee's base save area,
another base save area to manage gcc nested functions, and a little temporary
space to help manage the spilling of the register windows.
-------------------------------------------------------------------------------
*/
STRUCT_BEGIN
STRUCT_FIELD (long, 4, XT_STK_EXIT, exit) /* exit point for dispatch */
STRUCT_FIELD (long, 4, XT_STK_PC, pc) /* return PC */
STRUCT_FIELD (long, 4, XT_STK_PS, ps) /* return PS */
STRUCT_FIELD (long, 4, XT_STK_A0, a0)
STRUCT_FIELD (long, 4, XT_STK_A1, a1) /* stack pointer before interrupt */
STRUCT_FIELD (long, 4, XT_STK_A2, a2)
STRUCT_FIELD (long, 4, XT_STK_A3, a3)
STRUCT_FIELD (long, 4, XT_STK_A4, a4)
STRUCT_FIELD (long, 4, XT_STK_A5, a5)
STRUCT_FIELD (long, 4, XT_STK_A6, a6)
STRUCT_FIELD (long, 4, XT_STK_A7, a7)
STRUCT_FIELD (long, 4, XT_STK_A8, a8)
STRUCT_FIELD (long, 4, XT_STK_A9, a9)
STRUCT_FIELD (long, 4, XT_STK_A10, a10)
STRUCT_FIELD (long, 4, XT_STK_A11, a11)
STRUCT_FIELD (long, 4, XT_STK_A12, a12)
STRUCT_FIELD (long, 4, XT_STK_A13, a13)
STRUCT_FIELD (long, 4, XT_STK_A14, a14)
STRUCT_FIELD (long, 4, XT_STK_A15, a15)
STRUCT_FIELD (long, 4, XT_STK_SAR, sar)
STRUCT_FIELD (long, 4, XT_STK_EXCCAUSE, exccause)
STRUCT_FIELD (long, 4, XT_STK_EXCVADDR, excvaddr)
#if XCHAL_HAVE_LOOPS
STRUCT_FIELD (long, 4, XT_STK_LBEG, lbeg)
STRUCT_FIELD (long, 4, XT_STK_LEND, lend)
STRUCT_FIELD (long, 4, XT_STK_LCOUNT, lcount)
#endif
#ifndef __XTENSA_CALL0_ABI__
/* Temporary space for saving stuff during window spill */
STRUCT_FIELD (long, 4, XT_STK_TMP0, tmp0)
STRUCT_FIELD (long, 4, XT_STK_TMP1, tmp1)
STRUCT_FIELD (long, 4, XT_STK_TMP2, tmp2)
#endif
#ifdef XT_USE_SWPRI
/* Storage for virtual priority mask */
STRUCT_FIELD (long, 4, XT_STK_VPRI, vpri)
#endif
#ifdef XT_USE_OVLY
/* Storage for overlay state */
STRUCT_FIELD (long, 4, XT_STK_OVLY, ovly)
#endif
STRUCT_END(XtExcFrame)
#if defined(_ASMLANGUAGE) || defined(__ASSEMBLER__)
#define XT_STK_NEXT1 XtExcFrameSize
#else
#define XT_STK_NEXT1 sizeof(XtExcFrame)
#endif
/* Allocate extra storage if needed */
#if XCHAL_EXTRA_SA_SIZE != 0
#if XCHAL_EXTRA_SA_ALIGN <= 16
#define XT_STK_EXTRA ALIGNUP(XCHAL_EXTRA_SA_ALIGN, XT_STK_NEXT1)
#else
/* If need more alignment than stack, add space for dynamic alignment */
#define XT_STK_EXTRA (ALIGNUP(XCHAL_EXTRA_SA_ALIGN, XT_STK_NEXT1) + XCHAL_EXTRA_SA_ALIGN)
#endif
#define XT_STK_NEXT2 (XT_STK_EXTRA + XCHAL_EXTRA_SA_SIZE)
#else
#define XT_STK_NEXT2 XT_STK_NEXT1
#endif
/*
-------------------------------------------------------------------------------
This is the frame size. Add space for 4 registers (interruptee's base save
area) and some space for gcc nested functions if any.
-------------------------------------------------------------------------------
*/
#define XT_STK_FRMSZ (ALIGNUP(0x10, XT_STK_NEXT2) + 0x20)
/*
-------------------------------------------------------------------------------
SOLICITED STACK FRAME FOR A THREAD
A stack frame of this structure is allocated whenever a thread enters the
RTOS kernel intentionally (and synchronously) to submit to thread scheduling.
It goes on the current thread's stack.
The solicited frame only includes registers that are required to be preserved
by the callee according to the compiler's ABI conventions, some space to save
the return address for returning to the caller, and the caller's PS register.
For Windowed ABI, this stack frame includes the caller's base save area.
Note on XT_SOL_EXIT field:
It is necessary to distinguish a solicited from an interrupt stack frame.
This field corresponds to XT_STK_EXIT in the interrupt stack frame and is
always at the same offset (0). It can be written with a code (usually 0)
to distinguish a solicted frame from an interrupt frame. An RTOS port may
opt to ignore this field if it has another way of distinguishing frames.
-------------------------------------------------------------------------------
*/
STRUCT_BEGIN
#ifdef __XTENSA_CALL0_ABI__
STRUCT_FIELD (long, 4, XT_SOL_EXIT, exit)
STRUCT_FIELD (long, 4, XT_SOL_PC, pc)
STRUCT_FIELD (long, 4, XT_SOL_PS, ps)
STRUCT_FIELD (long, 4, XT_SOL_NEXT, next)
STRUCT_FIELD (long, 4, XT_SOL_A12, a12) /* should be on 16-byte alignment */
STRUCT_FIELD (long, 4, XT_SOL_A13, a13)
STRUCT_FIELD (long, 4, XT_SOL_A14, a14)
STRUCT_FIELD (long, 4, XT_SOL_A15, a15)
#else
STRUCT_FIELD (long, 4, XT_SOL_EXIT, exit)
STRUCT_FIELD (long, 4, XT_SOL_PC, pc)
STRUCT_FIELD (long, 4, XT_SOL_PS, ps)
STRUCT_FIELD (long, 4, XT_SOL_NEXT, next)
STRUCT_FIELD (long, 4, XT_SOL_A0, a0) /* should be on 16-byte alignment */
STRUCT_FIELD (long, 4, XT_SOL_A1, a1)
STRUCT_FIELD (long, 4, XT_SOL_A2, a2)
STRUCT_FIELD (long, 4, XT_SOL_A3, a3)
#endif
STRUCT_END(XtSolFrame)
/* Size of solicited stack frame */
#define XT_SOL_FRMSZ ALIGNUP(0x10, XtSolFrameSize)
/*
-------------------------------------------------------------------------------
CO-PROCESSOR STATE SAVE AREA FOR A THREAD
The RTOS must provide an area per thread to save the state of co-processors
when that thread does not have control. Co-processors are context-switched
lazily (on demand) only when a new thread uses a co-processor instruction,
otherwise a thread retains ownership of the co-processor even when it loses
control of the processor. An Xtensa co-processor exception is triggered when
any co-processor instruction is executed by a thread that is not the owner,
and the context switch of that co-processor is then peformed by the handler.
Ownership represents which thread's state is currently in the co-processor.
Co-processors may not be used by interrupt or exception handlers. If an
co-processor instruction is executed by an interrupt or exception handler,
the co-processor exception handler will trigger a kernel panic and freeze.
This restriction is introduced to reduce the overhead of saving and restoring
co-processor state (which can be quite large) and in particular remove that
overhead from interrupt handlers.
The co-processor state save area may be in any convenient per-thread location
such as in the thread control block or above the thread stack area. It need
not be in the interrupt stack frame since interrupts don't use co-processors.
Along with the save area for each co-processor, two bitmasks with flags per
co-processor (laid out as in the CPENABLE reg) help manage context-switching
co-processors as efficiently as possible:
XT_CPENABLE
The contents of a non-running thread's CPENABLE register.
It represents the co-processors owned (and whose state is still needed)
by the thread. When a thread is preempted, its CPENABLE is saved here.
When a thread solicits a context-swtich, its CPENABLE is cleared - the
compiler has saved the (caller-saved) co-proc state if it needs to.
When a non-running thread loses ownership of a CP, its bit is cleared.
When a thread runs, it's XT_CPENABLE is loaded into the CPENABLE reg.
Avoids co-processor exceptions when no change of ownership is needed.
XT_CPSTORED
A bitmask with the same layout as CPENABLE, a bit per co-processor.
Indicates whether the state of each co-processor is saved in the state
save area. When a thread enters the kernel, only the state of co-procs
still enabled in CPENABLE is saved. When the co-processor exception
handler assigns ownership of a co-processor to a thread, it restores
the saved state only if this bit is set, and clears this bit.
XT_CP_CS_ST
A bitmask with the same layout as CPENABLE, a bit per co-processor.
Indicates whether callee-saved state is saved in the state save area.
Callee-saved state is saved by itself on a solicited context switch,
and restored when needed by the coprocessor exception handler.
Unsolicited switches will cause the entire coprocessor to be saved
when necessary.
XT_CP_ASA
Pointer to the aligned save area. Allows it to be aligned more than
the overall save area (which might only be stack-aligned or TCB-aligned).
Especially relevant for Xtensa cores configured with a very large data
path that requires alignment greater than 16 bytes (ABI stack alignment).
-------------------------------------------------------------------------------
*/
#if XCHAL_CP_NUM > 0
/* Offsets of each coprocessor save area within the 'aligned save area': */
#define XT_CP0_SA 0
#define XT_CP1_SA ALIGNUP(XCHAL_CP1_SA_ALIGN, XT_CP0_SA + XCHAL_CP0_SA_SIZE)
#define XT_CP2_SA ALIGNUP(XCHAL_CP2_SA_ALIGN, XT_CP1_SA + XCHAL_CP1_SA_SIZE)
#define XT_CP3_SA ALIGNUP(XCHAL_CP3_SA_ALIGN, XT_CP2_SA + XCHAL_CP2_SA_SIZE)
#define XT_CP4_SA ALIGNUP(XCHAL_CP4_SA_ALIGN, XT_CP3_SA + XCHAL_CP3_SA_SIZE)
#define XT_CP5_SA ALIGNUP(XCHAL_CP5_SA_ALIGN, XT_CP4_SA + XCHAL_CP4_SA_SIZE)
#define XT_CP6_SA ALIGNUP(XCHAL_CP6_SA_ALIGN, XT_CP5_SA + XCHAL_CP5_SA_SIZE)
#define XT_CP7_SA ALIGNUP(XCHAL_CP7_SA_ALIGN, XT_CP6_SA + XCHAL_CP6_SA_SIZE)
#define XT_CP_SA_SIZE ALIGNUP(16, XT_CP7_SA + XCHAL_CP7_SA_SIZE)
/* Offsets within the overall save area: */
#define XT_CPENABLE 0 /* (2 bytes) coprocessors active for this thread */
#define XT_CPSTORED 2 /* (2 bytes) coprocessors saved for this thread */
#define XT_CP_CS_ST 4 /* (2 bytes) coprocessor callee-saved regs stored for this thread */
#define XT_CP_ASA 8 /* (4 bytes) ptr to aligned save area */
/* Overall size allows for dynamic alignment: */
#define XT_CP_SIZE (12 + XT_CP_SA_SIZE + XCHAL_TOTAL_SA_ALIGN)
#else
#define XT_CP_SIZE 0
#endif
/*
Macro to get the current core ID. Only uses the reg given as an argument.
Reading PRID on the ESP32 gives us 0xCDCD on the PRO processor (0)
and 0xABAB on the APP CPU (1). We can distinguish between the two by checking
bit 13: it's 1 on the APP and 0 on the PRO processor.
*/
#ifdef __ASSEMBLER__
.macro getcoreid reg
rsr.prid \reg
extui \reg,\reg,13,1
.endm
#endif
#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0))
#define CORE_ID_PRO 0xCDCD
#define CORE_ID_APP 0xABAB
#else
#define CORE_ID_REGVAL_PRO 0xCDCD
#define CORE_ID_REGVAL_APP 0xABAB
/* Included for compatibility, recommend using CORE_ID_REGVAL_PRO instead */
#define CORE_ID_PRO CORE_ID_REGVAL_PRO
/* Included for compatibility, recommend using CORE_ID_REGVAL_APP instead */
#define CORE_ID_APP CORE_ID_REGVAL_APP
#endif
/*
-------------------------------------------------------------------------------
MACROS TO HANDLE ABI SPECIFICS OF FUNCTION ENTRY AND RETURN
Convenient where the frame size requirements are the same for both ABIs.
ENTRY(sz), RET(sz) are for framed functions (have locals or make calls).
ENTRY0, RET0 are for frameless functions (no locals, no calls).
where size = size of stack frame in bytes (must be >0 and aligned to 16).
For framed functions the frame is created and the return address saved at
base of frame (Call0 ABI) or as determined by hardware (Windowed ABI).
For frameless functions, there is no frame and return address remains in a0.
Note: Because CPP macros expand to a single line, macros requiring multi-line
expansions are implemented as assembler macros.
-------------------------------------------------------------------------------
*/
#ifdef __ASSEMBLER__
#ifdef __XTENSA_CALL0_ABI__
/* Call0 */
#define ENTRY(sz) entry1 sz
.macro entry1 size=0x10
addi sp, sp, -\size
s32i a0, sp, 0
.endm
#define ENTRY0
#define RET(sz) ret1 sz
.macro ret1 size=0x10
l32i a0, sp, 0
addi sp, sp, \size
ret
.endm
#define RET0 ret
#else
/* Windowed */
#define ENTRY(sz) entry sp, sz
#define ENTRY0 entry sp, 0x10
#define RET(sz) retw
#define RET0 retw
#endif
#endif
#endif /* XTENSA_CONTEXT_H */
#include <xtensa/xtensa_context.h>

View File

@ -59,7 +59,7 @@
#include <xtensa/corebits.h>
#include <xtensa/config/system.h>
#include "sdkconfig.h"
/*
* Include any RTOS specific definitions that are needed by this header.
*/
@ -154,7 +154,9 @@
* RTOS may optionally define XT_TICK_PER_SEC in its own way (eg. macro).
*/
/* void XT_RTOS_TIMER_INT(void) */
#define XT_RTOS_TIMER_INT _frxt_timer_int
#ifdef CONFIG_FREERTOS_SYSTICK_USES_CCOUNT
#define XT_RTOS_TIMER_INT _frxt_timer_int
#endif
#define XT_TICK_PER_SEC configTICK_RATE_HZ
/*

View File

@ -1,5 +1,6 @@
/*
* SPDX-FileCopyrightText: 2020 Amazon.com, Inc. or its affiliates
* SPDX-FileCopyrightText: 2015-2019 Cadence Design Systems, Inc.
*
* SPDX-License-Identifier: MIT
*
@ -32,32 +33,31 @@
*
* 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.
* -----------------------------------------------------------------------------
/*
* Copyright (c) 2015-2019 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>
#include <string.h>
#include <xtensa/config/core.h>
#include "xtensa_rtos.h"
@ -68,7 +68,9 @@
#include "esp_panic.h"
#include "esp_crosscore_int.h"
#else
#if CONFIG_IDF_TARGET_ESP32S2
#if CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/rom/ets_sys.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/ets_sys.h"
#elif CONFIG_IDF_TARGET_ESP32
#include "esp32/rom/ets_sys.h"
@ -87,23 +89,16 @@
#include "esp_intr_alloc.h"
/* Defined in portasm.h */
extern void _frxt_tick_timer_init( void );
#include "port_systick.h"
/* Defined in xtensa_context.S */
extern void _xt_coproc_init( void );
#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
_Static_assert(tskNO_AFFINITY == CONFIG_FREERTOS_NO_AFFINITY, "incorrect tskNO_AFFINITY value");
/*-----------------------------------------------------------*/
unsigned port_xSchedulerRunning[ portNUM_PROCESSORS ] = { 0 }; /* Duplicate of inaccessible xSchedulerRunning; needed at startup to avoid counting nesting */
extern volatile int port_xSchedulerRunning[portNUM_PROCESSORS];
unsigned port_interruptNesting[ portNUM_PROCESSORS ] = { 0 }; /* Interrupt nesting level. Increased/decreased in portasm.c, _frxt_int_enter/_frxt_int_exit */
/*-----------------------------------------------------------*/
@ -148,8 +143,28 @@ void _xt_user_exit( void );
uint32_t * p;
#endif
uint32_t * threadptr;
void * task_thread_local_start;
extern int _thread_local_start, _thread_local_end, _flash_rodata_start, _flash_rodata_align;
/* TODO: check that TLS area fits the stack */
uint32_t thread_local_sz = ( uint8_t * ) &_thread_local_end - ( uint8_t * ) &_thread_local_start;
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.
*/
/* Create interrupt stack frame aligned to 16 byte boundary */
sp = ( StackType_t * ) ( ( ( UBaseType_t ) pxTopOfStack - XT_CP_SIZE - XT_STK_FRMSZ ) & ~0xf );
sp = ( StackType_t * ) ( ( ( UBaseType_t ) pxTopOfStack - XT_CP_SIZE - thread_local_sz - XT_STK_FRMSZ ) & ~0xf );
/* Clear the entire frame (do not use memset() because we don't depend on C library) */
for( tp = sp; tp <= pxTopOfStack; ++tp )
@ -195,6 +210,24 @@ void _xt_user_exit( void );
frame->vpri = 0xFFFFFFFF;
#endif
/* Init threadptr register and set up TLS run-time area. */
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 );
/* 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.
*/
const uint32_t tls_section_alignment = ( uint32_t ) &_flash_rodata_align; /* 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 ) &_flash_rodata_start ) - base;
#if XCHAL_CP_NUM > 0
/* Init the coprocessor save area (see xtensa_context.h) */
@ -217,12 +250,14 @@ void vPortEndScheduler( void )
{
/* It is unlikely that the Xtensa port will get stopped. If required simply
* disable the tick interrupt here. */
abort();
}
/*-----------------------------------------------------------*/
BaseType_t xPortStartScheduler( void )
{
portDISABLE_INTERRUPTS();
/* Interrupts are disabled at this point and stack contains PS with enabled interrupts when task context is restored */
#if XCHAL_CP_NUM > 0
@ -230,11 +265,21 @@ BaseType_t xPortStartScheduler( void )
_xt_coproc_init();
#endif
/* Init the tick divisor value */
_xt_tick_divisor_init();
/* Setup the hardware to generate the tick */
vPortSetupTimer();
/* Setup the hardware to generate the tick. */
_frxt_tick_timer_init();
/* NOTE: For ESP32-S3, vPortSetupTimer allocates an interrupt for the
* systimer which is used as the source for FreeRTOS systick.
*
* The behaviour of portEXIT_CRITICAL is different in FreeRTOS and ESP-IDF -
* the former enables the interrupts no matter what the state was at the beginning
* of the call while the latter restores the interrupt state to what was at the
* beginning of the call.
*
* This resulted in the interrupts being enabled before the _frxt_dispatch call,
* who was unable to switch context to the queued tasks.
*/
portDISABLE_INTERRUPTS();
port_xSchedulerRunning[ xPortGetCoreID() ] = 1;
@ -244,38 +289,9 @@ BaseType_t xPortStartScheduler( void )
/* Should not get here. */
return pdTRUE;
}
/*-----------------------------------------------------------*/
BaseType_t xPortSysTickHandler( void )
{
BaseType_t ret;
unsigned interruptMask;
portbenchmarkIntLatency();
traceISR_ENTER( SYSTICK_INTR_ID );
/* Interrupts upto configMAX_SYSCALL_INTERRUPT_PRIORITY must be
* disabled before calling xTaskIncrementTick as it access the
* kernel lists. */
interruptMask = portSET_INTERRUPT_MASK_FROM_ISR();
{
ret = xTaskIncrementTick();
}
portCLEAR_INTERRUPT_MASK_FROM_ISR( interruptMask );
if( ret != pdFALSE )
{
portYIELD_FROM_ISR();
}
else
{
traceISR_EXIT();
}
return ret;
}
void vPortYieldOtherCore( BaseType_t coreid )
{
esp_crosscore_int_send_yield( coreid );
@ -297,7 +313,6 @@ void vPortYieldOtherCore( BaseType_t coreid )
xMPUSettings->coproc_area = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) xMPUSettings->coproc_area ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );
xMPUSettings->coproc_area = ( StackType_t * ) ( ( ( uint32_t ) xMPUSettings->coproc_area - 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().
*/
@ -321,9 +336,9 @@ BaseType_t xPortInIsrContext()
unsigned int irqStatus;
BaseType_t ret;
irqStatus = portENTER_CRITICAL_NESTED();
irqStatus = portSET_INTERRUPT_MASK_FROM_ISR();
ret = ( port_interruptNesting[ xPortGetCoreID() ] != 0 );
portEXIT_CRITICAL_NESTED( irqStatus );
portCLEAR_INTERRUPT_MASK_FROM_ISR( irqStatus );
return ret;
}
@ -336,11 +351,39 @@ BaseType_t IRAM_ATTR xPortInterruptedFromISRContext()
return( port_interruptNesting[ xPortGetCoreID() ] != 0 );
}
void IRAM_ATTR vPortEvaluateYieldFromISR( int argc, ... )
{
BaseType_t xYield;
va_list ap;
va_start( ap, argc );
if( argc )
{
xYield = ( BaseType_t )va_arg( ap, int );
va_end( ap );
}
else
{
//it is a empty parameter vPortYieldFromISR macro call:
va_end( ap );
traceISR_EXIT_TO_SCHEDULER();
_frxt_setup_switch();
return;
}
//Yield exists, so need evaluate it first then switch:
if( xYield == pdTRUE )
{
traceISR_EXIT_TO_SCHEDULER();
_frxt_setup_switch();
}
}
void vPortAssertIfInISR()
{
if( xPortInIsrContext() )
{
ets_printf( "core=%d port_interruptNesting=%d\n\n", xPortGetCoreID(), port_interruptNesting[ xPortGetCoreID() ] );
esp_rom_printf( "core=%d port_interruptNesting=%d\n\n", xPortGetCoreID(), port_interruptNesting[ xPortGetCoreID() ] );
}
configASSERT( !xPortInIsrContext() );
@ -352,7 +395,7 @@ void vPortAssertIfInISR()
void vPortCPUInitializeMutex( portMUX_TYPE * mux )
{
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
ets_printf( "Initializing mux %p\n", mux );
esp_rom_printf( "Initializing mux %p\n", mux );
mux->lastLockedFn = "(never locked)";
mux->lastLockedLine = -1;
#endif
@ -370,10 +413,10 @@ void vPortCPUInitializeMutex( portMUX_TYPE * mux )
const char * fnName,
int line )
{
unsigned int irqStatus = portENTER_CRITICAL_NESTED();
unsigned int irqStatus = portSET_INTERRUPT_MASK_FROM_ISR();
vPortCPUAcquireMutexIntsDisabled( mux, portMUX_NO_TIMEOUT, fnName, line );
portEXIT_CRITICAL_NESTED( irqStatus );
portCLEAR_INTERRUPT_MASK_FROM_ISR( irqStatus );
}
bool vPortCPUAcquireMutexTimeout( portMUX_TYPE * mux,
@ -381,29 +424,29 @@ void vPortCPUInitializeMutex( portMUX_TYPE * mux )
const char * fnName,
int line )
{
unsigned int irqStatus = portENTER_CRITICAL_NESTED();
unsigned int irqStatus = portSET_INTERRUPT_MASK_FROM_ISR();
bool result = vPortCPUAcquireMutexIntsDisabled( mux, timeout_cycles, fnName, line );
portEXIT_CRITICAL_NESTED( irqStatus );
portCLEAR_INTERRUPT_MASK_FROM_ISR( irqStatus );
return result;
}
#else /* ifdef CONFIG_FREERTOS_PORTMUX_DEBUG */
void vPortCPUAcquireMutex( portMUX_TYPE * mux )
{
unsigned int irqStatus = portENTER_CRITICAL_NESTED();
unsigned int irqStatus = portSET_INTERRUPT_MASK_FROM_ISR();
vPortCPUAcquireMutexIntsDisabled( mux, portMUX_NO_TIMEOUT );
portEXIT_CRITICAL_NESTED( irqStatus );
portCLEAR_INTERRUPT_MASK_FROM_ISR( irqStatus );
}
bool vPortCPUAcquireMutexTimeout( portMUX_TYPE * mux,
int timeout_cycles )
{
unsigned int irqStatus = portENTER_CRITICAL_NESTED();
unsigned int irqStatus = portSET_INTERRUPT_MASK_FROM_ISR();
bool result = vPortCPUAcquireMutexIntsDisabled( mux, timeout_cycles );
portEXIT_CRITICAL_NESTED( irqStatus );
portCLEAR_INTERRUPT_MASK_FROM_ISR( irqStatus );
return result;
}
#endif /* ifdef CONFIG_FREERTOS_PORTMUX_DEBUG */
@ -419,21 +462,24 @@ void vPortCPUInitializeMutex( portMUX_TYPE * mux )
const char * fnName,
int line )
{
unsigned int irqStatus = portENTER_CRITICAL_NESTED();
unsigned int irqStatus = portSET_INTERRUPT_MASK_FROM_ISR();
vPortCPUReleaseMutexIntsDisabled( mux, fnName, line );
portEXIT_CRITICAL_NESTED( irqStatus );
portCLEAR_INTERRUPT_MASK_FROM_ISR( irqStatus );
}
#else
void vPortCPUReleaseMutex( portMUX_TYPE * mux )
{
unsigned int irqStatus = portENTER_CRITICAL_NESTED();
unsigned int irqStatus = portSET_INTERRUPT_MASK_FROM_ISR();
vPortCPUReleaseMutexIntsDisabled( mux );
portEXIT_CRITICAL_NESTED( irqStatus );
portCLEAR_INTERRUPT_MASK_FROM_ISR( irqStatus );
}
#endif /* ifdef CONFIG_FREERTOS_PORTMUX_DEBUG */
#define STACK_WATCH_AREA_SIZE ( 32 )
#define STACK_WATCH_POINT_NUMBER ( SOC_CPU_WATCHPOINTS_NUM - 1 )
void vPortSetStackWatchpoint( void * pxStackStart )
{
/*Set watchpoint 1 to watch the last 32 bytes of the stack. */
@ -445,7 +491,7 @@ void vPortSetStackWatchpoint( void * pxStackStart )
int addr = ( int ) pxStackStart;
addr = ( addr + 31 ) & ( ~31 );
esp_set_watchpoint( 1, ( char * ) addr, 32, ESP_WATCHPOINT_STORE );
esp_cpu_set_watchpoint( STACK_WATCH_POINT_NUMBER, (char*)addr, 32, ESP_WATCHPOINT_STORE );
}
#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0))
@ -463,7 +509,7 @@ void vPortSetStackWatchpoint( void * pxStackStart )
{
uint32_t prev;
uint32_t oldlevel = portENTER_CRITICAL_NESTED();
uint32_t oldlevel = portSET_INTERRUPT_MASK_FROM_ISR();
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
vPortCPUAcquireMutexIntsDisabled( &extram_mux, portMUX_NO_TIMEOUT, __FUNCTION__, __LINE__ );
@ -484,7 +530,7 @@ void vPortSetStackWatchpoint( void * pxStackStart )
vPortCPUReleaseMutexIntsDisabled( &extram_mux );
#endif
portEXIT_CRITICAL_NESTED(oldlevel);
portCLEAR_INTERRUPT_MASK_FROM_ISR(oldlevel);
}
#endif //defined(CONFIG_SPIRAM_SUPPORT)
@ -495,3 +541,28 @@ uint32_t xPortGetTickRateHz( void )
{
return ( uint32_t ) configTICK_RATE_HZ;
}
// For now, running FreeRTOS on one core and a bare metal on the other (or other OSes)
// is not supported. For now CONFIG_FREERTOS_UNICORE and CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
// should mirror each other's values.
//
// And since this should be true, we can just check for CONFIG_FREERTOS_UNICORE.
#if CONFIG_FREERTOS_UNICORE != CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
#error "FreeRTOS and system configuration mismatch regarding the use of multiple cores."
#endif
extern void esp_startup_start_app_common(void);
void esp_startup_start_app(void)
{
#if !CONFIG_ESP_INT_WDT
#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_startup_start_app_common();
ESP_LOGI("cpu_start", "Starting scheduler on PRO CPU.");
vTaskStartScheduler();
}

View File

@ -0,0 +1,159 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include "FreeRTOS.h"
#include "task.h"
#include "portmacro.h"
#include "esp_system.h"
#include "esp_heap_caps_init.h"
#include "esp_int_wdt.h"
#include "esp_task_wdt.h"
#include "esp_task.h"
#include "esp_private/crosscore_int.h"
#include "esp_private/startup_internal.h" /* Required by g_spiram_ok. [refactor-todo] for g_spiram_ok */
#include "esp_log.h"
#include "soc/soc_memory_types.h"
#include "soc/dport_access.h"
#include "sdkconfig.h"
#include "esp_freertos_hooks.h"
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/spiram.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/spiram.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/spiram.h"
#elif CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32H2
// SPIRAM is not supported on ESP32-C3
#endif
#if CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL
static const char* TAG = "cpu_start";
#endif
/* Architecture-agnostic parts of the FreeRTOS ESP-IDF port layer can go here.
*
* The actual call flow will be to call esp_startup_start_app() in <ARCH>/port.c,
* which will then call esp_startup_start_app_common()
*/
// Duplicate of inaccessible xSchedulerRunning; needed at startup to avoid counting nesting
volatile unsigned port_xSchedulerRunning[portNUM_PROCESSORS] = {0};
// For now, running FreeRTOS on one core and a bare metal on the other (or other OSes)
// is not supported. For now CONFIG_FREERTOS_UNICORE and CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
// should mirror each other's values.
//
// And since this should be true, we can just check for CONFIG_FREERTOS_UNICORE.
#if CONFIG_FREERTOS_UNICORE != CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
#error "FreeRTOS and system configuration mismatch regarding the use of multiple cores."
#endif
static void main_task(void* args);
#ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
void esp_gdbstub_init(void);
#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
extern void app_main(void);
void esp_startup_start_app_common(void)
{
#if CONFIG_ESP_INT_WDT
esp_int_wdt_init();
//Initialize the interrupt watch dog for CPU0.
esp_int_wdt_cpu_init();
#endif
esp_crosscore_int_init();
#ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
esp_gdbstub_init();
#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, "main",
ESP_TASK_MAIN_STACK, NULL,
ESP_TASK_MAIN_PRIO, NULL, ESP_TASK_MAIN_CORE);
assert(res == pdTRUE);
(void)res;
}
#if !CONFIG_FREERTOS_UNICORE
static volatile bool s_other_cpu_startup_done = false;
static bool other_cpu_startup_idle_hook_cb(void)
{
s_other_cpu_startup_done = true;
return true;
}
#endif
static void main_task(void* args)
{
#if !CONFIG_FREERTOS_UNICORE
// Wait for FreeRTOS initialization to finish on other core, before replacing its startup stack
esp_register_freertos_idle_hook_for_cpu(other_cpu_startup_idle_hook_cb, !xPortGetCoreID());
while (!s_other_cpu_startup_done) {
;
}
esp_deregister_freertos_idle_hook_for_cpu(other_cpu_startup_idle_hook_cb, !xPortGetCoreID());
#endif
// [refactor-todo] check if there is a way to move the following block to esp_system startup
heap_caps_enable_nonos_stack_heaps();
// Now we have startup stack RAM available for heap, enable any DMA pool memory
#if CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL
if (g_spiram_ok) {
esp_err_t r = esp_spiram_reserve_dma_pool(CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL);
if (r != ESP_OK) {
ESP_EARLY_LOGE(TAG, "Could not reserve internal/DMA pool (error 0x%x)", r);
abort();
}
}
#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
app_main();
vTaskDelete(NULL);
}
// -------------------- Heap Related -----------------------
bool xPortCheckValidTCBMem(const void *ptr)
{
return esp_ptr_internal(ptr) && esp_ptr_byte_accessible(ptr);
}
bool xPortcheckValidStackMem(const void *ptr)
{
#ifdef CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
return esp_ptr_byte_accessible(ptr);
#else
return esp_ptr_internal(ptr) && esp_ptr_byte_accessible(ptr);
#endif
}

View File

@ -0,0 +1,174 @@
/*
* SPDX-FileCopyrightText: 2017-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdlib.h>
#include <string.h>
#include "soc/cpu.h"
#include "FreeRTOS.h"
#include "task.h"
#include "esp_intr_alloc.h"
#include "esp_err.h"
#include "esp_log.h"
#include "sdkconfig.h"
#ifdef CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER
#include "soc/periph_defs.h"
#include "soc/system_reg.h"
#include "hal/systimer_hal.h"
#include "hal/systimer_ll.h"
#endif
#ifdef CONFIG_PM_TRACE
#include "esp_private/pm_trace.h"
#endif //CONFIG_PM_TRACE
BaseType_t xPortSysTickHandler(void);
#ifdef CONFIG_FREERTOS_SYSTICK_USES_CCOUNT
extern void _frxt_tick_timer_init(void);
extern void _xt_tick_divisor_init(void);
#ifdef CONFIG_FREERTOS_CORETIMER_0
#define SYSTICK_INTR_ID (ETS_INTERNAL_TIMER0_INTR_SOURCE+ETS_INTERNAL_INTR_SOURCE_OFF)
#endif
#ifdef CONFIG_FREERTOS_CORETIMER_1
#define SYSTICK_INTR_ID (ETS_INTERNAL_TIMER1_INTR_SOURCE+ETS_INTERNAL_INTR_SOURCE_OFF)
#endif
/**
* @brief Initialize CCONT timer to generate the tick interrupt
*
*/
void vPortSetupTimer(void)
{
/* Init the tick divisor value */
_xt_tick_divisor_init();
_frxt_tick_timer_init();
}
#elif CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER
_Static_assert(SOC_CPU_CORES_NUM <= SOC_SYSTIMER_ALARM_NUM - 1, "the number of cores must match the number of core alarms in SYSTIMER");
void SysTickIsrHandler(void *arg);
static uint32_t s_handled_systicks[portNUM_PROCESSORS] = { 0 };
#define SYSTICK_INTR_ID (ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE)
/**
* @brief Set up the systimer peripheral to generate the tick interrupt
*
* Both timer alarms are configured in periodic mode.
* It is done at the same time so SysTicks for both CPUs occur at the same time or very close.
* Shifts a time of triggering interrupts for core 0 and core 1.
*/
void vPortSetupTimer(void)
{
unsigned cpuid = xPortGetCoreID();
#ifdef CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL3
const unsigned level = ESP_INTR_FLAG_LEVEL3;
#else
const unsigned level = ESP_INTR_FLAG_LEVEL1;
#endif
/* Systimer HAL layer object */
static systimer_hal_context_t systimer_hal;
/* set system timer interrupt vector */
ESP_ERROR_CHECK(esp_intr_alloc(ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE + cpuid, ESP_INTR_FLAG_IRAM | level, SysTickIsrHandler, &systimer_hal, NULL));
if (cpuid == 0) {
systimer_hal_init(&systimer_hal);
systimer_ll_set_counter_value(systimer_hal.dev, SYSTIMER_LL_COUNTER_OS_TICK, 0);
systimer_ll_apply_counter_value(systimer_hal.dev, SYSTIMER_LL_COUNTER_OS_TICK);
for (cpuid = 0; cpuid < SOC_CPU_CORES_NUM; cpuid++) {
systimer_hal_counter_can_stall_by_cpu(&systimer_hal, SYSTIMER_LL_COUNTER_OS_TICK, cpuid, false);
}
for (cpuid = 0; cpuid < portNUM_PROCESSORS; ++cpuid) {
uint32_t alarm_id = SYSTIMER_LL_ALARM_OS_TICK_CORE0 + cpuid;
/* configure the timer */
systimer_hal_connect_alarm_counter(&systimer_hal, alarm_id, SYSTIMER_LL_COUNTER_OS_TICK);
systimer_hal_set_alarm_period(&systimer_hal, alarm_id, 1000000UL / CONFIG_FREERTOS_HZ);
systimer_hal_select_alarm_mode(&systimer_hal, alarm_id, SYSTIMER_ALARM_MODE_PERIOD);
systimer_hal_counter_can_stall_by_cpu(&systimer_hal, SYSTIMER_LL_COUNTER_OS_TICK, cpuid, true);
if (cpuid == 0) {
systimer_hal_enable_alarm_int(&systimer_hal, alarm_id);
systimer_hal_enable_counter(&systimer_hal, SYSTIMER_LL_COUNTER_OS_TICK);
#ifndef CONFIG_FREERTOS_UNICORE
// SysTick of core 0 and core 1 are shifted by half of period
systimer_hal_counter_value_advance(&systimer_hal, SYSTIMER_LL_COUNTER_OS_TICK, 1000000UL / CONFIG_FREERTOS_HZ / 2);
#endif
}
}
} else {
uint32_t alarm_id = SYSTIMER_LL_ALARM_OS_TICK_CORE0 + cpuid;
systimer_hal_enable_alarm_int(&systimer_hal, alarm_id);
}
}
/**
* @brief Systimer interrupt handler.
*
* The Systimer interrupt for SysTick works in periodic mode no need to calc the next alarm.
* If a timer interrupt is ever serviced more than one tick late, it is necessary to process multiple ticks.
*/
IRAM_ATTR void SysTickIsrHandler(void *arg)
{
uint32_t cpuid = xPortGetCoreID();
systimer_hal_context_t *systimer_hal = (systimer_hal_context_t *)arg;
#ifdef CONFIG_PM_TRACE
ESP_PM_TRACE_ENTER(TICK, cpuid);
#endif
uint32_t alarm_id = SYSTIMER_LL_ALARM_OS_TICK_CORE0 + cpuid;
do {
systimer_ll_clear_alarm_int(systimer_hal->dev, alarm_id);
uint32_t diff = systimer_hal_get_counter_value(systimer_hal, SYSTIMER_LL_COUNTER_OS_TICK) / systimer_ll_get_alarm_period(systimer_hal->dev, alarm_id) - s_handled_systicks[cpuid];
if (diff > 0) {
if (s_handled_systicks[cpuid] == 0) {
s_handled_systicks[cpuid] = diff;
diff = 1;
} else {
s_handled_systicks[cpuid] += diff;
}
do {
xPortSysTickHandler();
} while (--diff);
}
} while (systimer_ll_is_alarm_int_fired(systimer_hal->dev, alarm_id));
#ifdef CONFIG_PM_TRACE
ESP_PM_TRACE_EXIT(TICK, cpuid);
#endif
}
#endif // CONFIG_FREERTOS_SYSTICK_USES_CCOUNT
/**
* @brief Handler of SysTick
*
* The function is called from:
* - _frxt_timer_int for xtensa with CONFIG_FREERTOS_SYSTICK_USES_CCOUNT
* - SysTickIsrHandler for xtensa with CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER
* - SysTickIsrHandler for riscv
*/
BaseType_t xPortSysTickHandler(void)
{
portbenchmarkIntLatency();
traceISR_ENTER(SYSTICK_INTR_ID);
BaseType_t ret = xTaskIncrementTick();
if(ret != pdFALSE) {
portYIELD_FROM_ISR();
} else {
traceISR_EXIT();
}
return ret;
}

View File

@ -282,6 +282,7 @@ _frxt_int_exit:
*
**********************************************************************************************************
*/
#ifdef CONFIG_FREERTOS_SYSTICK_USES_CCOUNT
.globl _frxt_timer_int
.type _frxt_timer_int,@function
.align 4
@ -333,7 +334,7 @@ _frxt_timer_int:
s32i a3, sp, 8
#endif
/* Call the FreeRTOS tick handler (see port.c). */
/* Call the FreeRTOS tick handler (see port_systick.c). */
#ifdef __XTENSA_CALL0_ABI__
call0 xPortSysTickHandler
#else
@ -359,6 +360,7 @@ _frxt_timer_int:
#endif // CONFIG_PM_TRACE
RET(16)
#endif // CONFIG_FREERTOS_SYSTICK_USES_CCOUNT
/*
**********************************************************************************************************
@ -370,6 +372,7 @@ _frxt_timer_int:
*
**********************************************************************************************************
*/
#ifdef CONFIG_FREERTOS_SYSTICK_USES_CCOUNT
.globl _frxt_tick_timer_init
.type _frxt_tick_timer_init,@function
.align 4
@ -402,6 +405,7 @@ _frxt_tick_timer_init:
#endif
RET(16)
#endif // CONFIG_FREERTOS_SYSTICK_USES_CCOUNT
/*
**********************************************************************************************************
@ -456,6 +460,10 @@ _frxt_dispatch:
.L_frxt_dispatch_sol:
/* Solicited stack frame. Restore minimal context and return from vPortYield(). */
#if XCHAL_HAVE_THREADPTR
l32i a2, sp, XT_SOL_THREADPTR
wur.threadptr a2
#endif
l32i a3, sp, XT_SOL_PS
#ifdef __XTENSA_CALL0_ABI__
l32i a12, sp, XT_SOL_A12
@ -543,6 +551,10 @@ vPortYield:
rsr a2, PS
s32i a0, sp, XT_SOL_PC
s32i a2, sp, XT_SOL_PS
#if XCHAL_HAVE_THREADPTR
rur.threadptr a2
s32i a2, sp, XT_SOL_THREADPTR
#endif
#ifdef __XTENSA_CALL0_ABI__
s32i a12, sp, XT_SOL_A12 /* save callee-saved registers */
s32i a13, sp, XT_SOL_A13

View File

@ -39,34 +39,37 @@
#ifdef XT_BOARD
#include <xtensa/xtbsp.h>
#include "xtensa/xtbsp.h"
#endif
#include "xtensa_rtos.h"
#include "xtensa_rtos.h"
#include "sdkconfig.h"
#include "esp_idf_version.h"
#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0))
#include "esp_clk.h"
#else
#if CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/clk.h"
#elif CONFIG_IDF_TARGET_ESP32
#include "esp32/clk.h"
#if CONFIG_IDF_TARGET_ESP32
#include "esp32/clk.h"
#elif CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/clk.h"
#elif CONFIG_IDF_TARGET_ESP32S3
#include "esp32s3/clk.h"
#endif
#endif /* ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0) */
#ifdef XT_RTOS_TIMER_INT
unsigned _xt_tick_divisor = 0; /* cached number of cycles per tick */
unsigned _xt_tick_divisor = 0; /* cached number of cycles per tick */
void _xt_tick_divisor_init( void )
{
_xt_tick_divisor = esp_clk_cpu_freq() / XT_TICK_PER_SEC;
}
void _xt_tick_divisor_init(void)
{
_xt_tick_divisor = esp_clk_cpu_freq() / XT_TICK_PER_SEC;
}
/* Deprecated, to be removed */
int xt_clock_freq( void )
{
return esp_clk_cpu_freq();
}
int xt_clock_freq(void)
{
return esp_clk_cpu_freq();
}
#endif /* XT_RTOS_TIMER_INT */

View File

@ -1,190 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2019 Cadence Design Systems, Inc.
*
* SPDX-License-Identifier: MIT
*
* SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD
*/
/*
* Copyright (c) 2015-2019 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.
*/
/******************************************************************************
* Xtensa-specific interrupt and exception functions for RTOS ports.
* Also see xtensa_intr_asm.S.
******************************************************************************/
#include <stdlib.h>
#include <xtensa/config/core.h>
#include "freertos/FreeRTOS.h"
#include "freertos/xtensa_api.h"
#include "freertos/portable.h"
#include "esp_idf_version.h"
#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0))
#include "rom/ets_sys.h"
#else
#if CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/rom/ets_sys.h"
#elif CONFIG_IDF_TARGET_ESP32
#include "esp32/rom/ets_sys.h"
#endif
#endif /* ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0) */
#if XCHAL_HAVE_EXCEPTIONS
/* Handler table is in xtensa_intr_asm.S */
extern xt_exc_handler _xt_exception_table[ XCHAL_EXCCAUSE_NUM * portNUM_PROCESSORS ];
/*
* Default handler for unhandled exceptions.
* CHANGED: We do this in panic.c now
*/
/*void xt_unhandled_exception(XtExcFrame *frame) */
/*{ */
/*exit(-1); */
/*} */
extern void xt_unhandled_exception( XtExcFrame * frame );
/*
* This function registers a handler for the specified exception.
* The function returns the address of the previous handler.
* On error, it returns 0.
*/
xt_exc_handler xt_set_exception_handler( int n,
xt_exc_handler f )
{
xt_exc_handler old;
if( ( n < 0 ) || ( n >= XCHAL_EXCCAUSE_NUM ) )
{
return 0; /* invalid exception number */
}
/* Convert exception number to _xt_exception_table name */
n = n * portNUM_PROCESSORS + xPortGetCoreID();
old = _xt_exception_table[ n ];
if( f )
{
_xt_exception_table[ n ] = f;
}
else
{
_xt_exception_table[ n ] = &xt_unhandled_exception;
}
return( ( old == &xt_unhandled_exception ) ? 0 : old );
}
#endif /* if XCHAL_HAVE_EXCEPTIONS */
#if XCHAL_HAVE_INTERRUPTS
/* Handler table is in xtensa_intr_asm.S */
typedef struct xt_handler_table_entry
{
void * handler;
void * arg;
} xt_handler_table_entry;
extern xt_handler_table_entry _xt_interrupt_table[ XCHAL_NUM_INTERRUPTS * portNUM_PROCESSORS ];
/*
* Default handler for unhandled interrupts.
*/
void xt_unhandled_interrupt( void * arg )
{
ets_printf( "Unhandled interrupt %d on cpu %d!\n", ( int ) arg, xPortGetCoreID() );
}
/*
* This function registers a handler for the specified interrupt. The "arg"
* parameter specifies the argument to be passed to the handler when it is
* invoked. The function returns the address of the previous handler.
* On error, it returns 0.
*/
xt_handler xt_set_interrupt_handler( int n,
xt_handler f,
void * arg )
{
xt_handler_table_entry * entry;
xt_handler old;
if( ( n < 0 ) || ( n >= XCHAL_NUM_INTERRUPTS ) )
{
return 0; /* invalid interrupt number */
}
if( Xthal_intlevel[ n ] > XCHAL_EXCM_LEVEL )
{
return 0; /* priority level too high to safely handle in C */
}
/* Convert exception number to _xt_exception_table name */
n = n * portNUM_PROCESSORS + xPortGetCoreID();
entry = _xt_interrupt_table + n;
old = entry->handler;
if( f )
{
entry->handler = f;
entry->arg = arg;
}
else
{
entry->handler = &xt_unhandled_interrupt;
entry->arg = ( void * ) n;
}
return( ( old == &xt_unhandled_interrupt ) ? 0 : old );
}
#if CONFIG_SYSVIEW_ENABLE
void * xt_get_interrupt_handler_arg( int n )
{
xt_handler_table_entry * entry;
if( ( n < 0 ) || ( n >= XCHAL_NUM_INTERRUPTS ) )
{
return 0; /* invalid interrupt number */
}
/* Convert exception number to _xt_exception_table name */
n = n * portNUM_PROCESSORS + xPortGetCoreID();
entry = _xt_interrupt_table + n;
return entry->arg;
}
#endif /* if CONFIG_SYSVIEW_ENABLE */
#endif /* XCHAL_HAVE_INTERRUPTS */

View File

@ -1,232 +0,0 @@
/*
* SPDX-FileCopyrightText: 2015-2019 Cadence Design Systems, Inc.
*
* SPDX-License-Identifier: MIT
*
* SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD
*/
/*
* Copyright (c) 2015-2019 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.
*/
/******************************************************************************
Xtensa interrupt handling data and assembly routines.
Also see xtensa_intr.c and xtensa_vectors.S.
******************************************************************************/
#include <xtensa/hal.h>
#include <xtensa/config/core.h>
#include "xtensa_context.h"
#include "FreeRTOSConfig.h"
#if XCHAL_HAVE_INTERRUPTS
/*
-------------------------------------------------------------------------------
INTENABLE virtualization information.
-------------------------------------------------------------------------------
*/
#if XT_USE_SWPRI
/* Warning - this is not multicore-compatible. */
.data
.global _xt_intdata
.align 8
_xt_intdata:
.global _xt_intenable
.type _xt_intenable,@object
.size _xt_intenable,4
.global _xt_vpri_mask
.type _xt_vpri_mask,@object
.size _xt_vpri_mask,4
_xt_intenable: .word 0 /* Virtual INTENABLE */
_xt_vpri_mask: .word 0xFFFFFFFF /* Virtual priority mask */
#endif
/*
-------------------------------------------------------------------------------
Table of C-callable interrupt handlers for each interrupt. Note that not all
slots can be filled, because interrupts at level > EXCM_LEVEL will not be
dispatched to a C handler by default.
Stored as:
int 0 cpu 0
int 0 cpu 1
...
int 0 cpu n
int 1 cpu 0
int 1 cpu 1
etc
-------------------------------------------------------------------------------
*/
.data
.global _xt_interrupt_table
.align 8
_xt_interrupt_table:
.set i, 0
.rept XCHAL_NUM_INTERRUPTS*portNUM_PROCESSORS
.word xt_unhandled_interrupt /* handler address */
.word i /* handler arg (default: intnum) */
.set i, i+1
.endr
#endif /* XCHAL_HAVE_INTERRUPTS */
#if XCHAL_HAVE_EXCEPTIONS
/*
-------------------------------------------------------------------------------
Table of C-callable exception handlers for each exception. Note that not all
slots will be active, because some exceptions (e.g. coprocessor exceptions)
are always handled by the OS and cannot be hooked by user handlers.
Stored as:
exc 0 cpu 0
exc 0 cpu 1
...
exc 0 cpu n
exc 1 cpu 0
exc 1 cpu 1
etc
-------------------------------------------------------------------------------
*/
.data
.global _xt_exception_table
.align 4
_xt_exception_table:
.rept XCHAL_EXCCAUSE_NUM * portNUM_PROCESSORS
.word xt_unhandled_exception /* handler address */
.endr
#endif
/*
-------------------------------------------------------------------------------
unsigned int xt_ints_on ( unsigned int mask )
Enables a set of interrupts. Does not simply set INTENABLE directly, but
computes it as a function of the current virtual priority if XT_USE_SWPRI is
enabled.
Can be called from interrupt handlers.
-------------------------------------------------------------------------------
*/
.text
.align 4
.global xt_ints_on
.type xt_ints_on,@function
xt_ints_on:
ENTRY0
#if XCHAL_HAVE_INTERRUPTS
#if XT_USE_SWPRI
movi a3, 0
movi a4, _xt_intdata
xsr a3, INTENABLE /* Disables all interrupts */
rsync
l32i a3, a4, 0 /* a3 = _xt_intenable */
l32i a6, a4, 4 /* a6 = _xt_vpri_mask */
or a5, a3, a2 /* a5 = _xt_intenable | mask */
s32i a5, a4, 0 /* _xt_intenable |= mask */
and a5, a5, a6 /* a5 = _xt_intenable & _xt_vpri_mask */
wsr a5, INTENABLE /* Reenable interrupts */
mov a2, a3 /* Previous mask */
#else
movi a3, 0
xsr a3, INTENABLE /* Disables all interrupts */
rsync
or a2, a3, a2 /* set bits in mask */
wsr a2, INTENABLE /* Re-enable ints */
rsync
mov a2, a3 /* return prev mask */
#endif
#else
movi a2, 0 /* Return zero */
#endif
RET0
.size xt_ints_on, . - xt_ints_on
/*
-------------------------------------------------------------------------------
unsigned int xt_ints_off ( unsigned int mask )
Disables a set of interrupts. Does not simply set INTENABLE directly,
but computes it as a function of the current virtual priority if XT_USE_SWPRI is
enabled.
Can be called from interrupt handlers.
-------------------------------------------------------------------------------
*/
.text
.align 4
.global xt_ints_off
.type xt_ints_off,@function
xt_ints_off:
ENTRY0
#if XCHAL_HAVE_INTERRUPTS
#if XT_USE_SWPRI
movi a3, 0
movi a4, _xt_intdata
xsr a3, INTENABLE /* Disables all interrupts */
rsync
l32i a3, a4, 0 /* a3 = _xt_intenable */
l32i a6, a4, 4 /* a6 = _xt_vpri_mask */
or a5, a3, a2 /* a5 = _xt_intenable | mask */
xor a5, a5, a2 /* a5 = _xt_intenable & ~mask */
s32i a5, a4, 0 /* _xt_intenable &= ~mask */
and a5, a5, a6 /* a5 = _xt_intenable & _xt_vpri_mask */
wsr a5, INTENABLE /* Reenable interrupts */
mov a2, a3 /* Previous mask */
#else
movi a4, 0
xsr a4, INTENABLE /* Disables all interrupts */
rsync
or a3, a4, a2 /* set bits in mask */
xor a3, a3, a2 /* invert bits in mask set in mask, essentially clearing them */
wsr a3, INTENABLE /* Re-enable ints */
rsync
mov a2, a4 /* return prev mask */
#endif
#else
movi a2, 0 /* return zero */
#endif
RET0
.size xt_ints_off, . - xt_ints_off

View File

@ -29,6 +29,21 @@ The default behaviour is to just exit the interrupt or call the panic handler on
.align 4
_xt_debugexception:
#if (CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_BTDM_CTRL_HLI)
#define XT_DEBUGCAUSE_DI (5)
getcoreid a0
#if (CONFIG_BTDM_CTRL_PINNED_TO_CORE == PRO_CPU_NUM)
beqz a0, 1f
#else
bnez a0, 1f
#endif
rsr a0, DEBUGCAUSE
extui a0, a0, XT_DEBUGCAUSE_DI, 1
bnez a0, _xt_debug_di_exc
1:
#endif //(CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_BTDM_CTRL_HLI)
movi a0,PANIC_RSN_DEBUGEXCEPTION
wsr a0,EXCCAUSE
/* _xt_panic assumes a level 1 exception. As we're
@ -41,6 +56,66 @@ _xt_debugexception:
call0 _xt_panic /* does not return */
rfi XCHAL_DEBUGLEVEL
#if (CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_BTDM_CTRL_HLI)
.align 4
_xt_debug_di_exc:
/*
The delay time can be calculated by the following formula:
T = ceil(0.25 + max(t1, t2)) us
t1 = 80 / f1, t2 = (1 + 14/N) * 20 / f2
f1: PSRAM access frequency, unit: MHz.
f2: Flash access frequency, unit: MHz.
When flash is slow/fast read, N = 1.
When flash is DOUT/DIO read, N = 2.
When flash is QOUT/QIO read, N = 4.
And after testing, when CPU frequency is 240 MHz, it will take 1us to loop 27 times.
*/
#if defined(CONFIG_ESPTOOLPY_FLASHMODE_QIO) || defined(CONFIG_ESPTOOLPY_FLASHMODE_QOUT)
# if defined(CONFIG_ESPTOOLPY_FLASHFREQ_80M) && defined(CONFIG_SPIRAM_SPEED_80M)
movi a0, 54
# elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_80M) && defined(CONFIG_SPIRAM_SPEED_40M)
movi a0, 81
# elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_40M) && defined(CONFIG_SPIRAM_SPEED_40M)
movi a0, 81
# elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_26M) && defined(CONFIG_SPIRAM_SPEED_40M)
movi a0, 108
# else
movi a0, 135
# endif
#elif defined(CONFIG_ESPTOOLPY_FLASHMODE_DIO) || defined(CONFIG_ESPTOOLPY_FLASHMODE_DOUT)
# if defined(CONFIG_ESPTOOLPY_FLASHFREQ_80M) && defined(CONFIG_SPIRAM_SPEED_80M)
movi a0, 81
# elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_80M) && defined(CONFIG_SPIRAM_SPEED_40M)
movi a0, 81
# elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_40M) && defined(CONFIG_SPIRAM_SPEED_40M)
movi a0, 135
# elif defined(CONFIG_ESPTOOLPY_FLASHFREQ_26M) && defined(CONFIG_SPIRAM_SPEED_40M)
movi a0, 189
# else
movi a0, 243
# endif
#else
movi a0, 243
#endif
1: addi a0, a0, -1 /* delay_us(N) */
.rept 4
nop
.endr
bnez a0, 1b
rsr a0, EXCSAVE+XCHAL_DEBUGLEVEL
rfi XCHAL_DEBUGLEVEL
#endif //(CONFIG_ESP32_ECO3_CACHE_LOCK_FIX && CONFIG_BTDM_CTRL_HLI)
#endif /* Debug exception */
@ -158,4 +233,3 @@ _xt_nmi:
rfi XCHAL_NMILEVEL
#endif /* NMI */

View File

@ -306,9 +306,13 @@
rsil a3, \level - 1 /* lower interrupt level by 1 */
#endif
#ifdef XT_RTOS_TIMER_INT
movi a3, XT_TIMER_INTEN /* a3 = timer interrupt bit */
wsr a4, INTCLEAR /* clear sw or edge-triggered interrupt */
beq a3, a4, 7f /* if timer interrupt then skip table */
#else
wsr a4, INTCLEAR /* clear sw or edge-triggered interrupt */
#endif // XT_RTOS_TIMER_INT
find_ms_setbit a3, a4, a3, 0 /* a3 = interrupt number */
@ -332,7 +336,7 @@
#else
j .L_xt_user_int_&level& /* check for more interrupts */
#endif
#ifdef XT_RTOS_TIMER_INT
7:
.ifeq XT_TIMER_INTPRI - \level
@ -352,6 +356,7 @@
call4 XT_RTOS_TIMER_INT
#endif
.endif
#endif // XT_RTOS_TIMER_INT
#ifdef XT_USE_SWPRI
j 8f
@ -377,7 +382,7 @@
.endm
#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0))
/*
--------------------------------------------------------------------------------
Panic handler.
@ -460,14 +465,12 @@ panic_print_hex_ok:
s32i a5,a3,0
ret
#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0) */
.section .rodata, "a"
.align 4
/*
--------------------------------------------------------------------------------
Hooks to dynamically install handlers for exceptions and interrupts.
@ -737,11 +740,11 @@ _xt_user_exc:
rsr a0, EXCSAVE_1 /* save interruptee's a0 */
s32i a0, sp, XT_STK_A0
/* Set up PS for C, reenable hi-pri interrupts, and clear EXCM. */
/* Set up PS for C, reenable debug and NMI interrupts, and clear EXCM. */
#ifdef __XTENSA_CALL0_ABI__
movi a0, PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM
movi a0, PS_INTLEVEL(XCHAL_DEBUGLEVEL - 2) | PS_UM
#else
movi a0, PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | PS_WOE
movi a0, PS_INTLEVEL(XCHAL_DEBUGLEVEL - 2) | PS_UM | PS_WOE
#endif
wsr a0, PS
@ -2062,6 +2065,3 @@ _WindowUnderflow12:
.type call_user_start,@function
.align 4
.literal_position