Update ESP32 port files to work with ESP-IDF v4.2 as well as ESP-IDF v3.3

Add changes required to support ESP32-S2
This commit is contained in:
Shubham Kulkarni 2020-07-31 09:28:51 +05:30 committed by David Chalco
parent 7a3f594733
commit 14b681ab6e
13 changed files with 514 additions and 33 deletions

View file

@ -19,6 +19,9 @@
#define USED
#endif
#ifdef CONFIG_ESP32_DEBUG_OCDAWARE
const int USED DRAM_ATTR uxTopUsedPriority = configMAX_PRIORITIES - 1;
#endif
/*
* This file is no longer needed as AFTER FreeRTOS V10.14.1 OpenOCD is fixed in the kernel.
* #ifdef CONFIG_ESP32_DEBUG_OCDAWARE
* const int USED DRAM_ATTR uxTopUsedPriority = configMAX_PRIORITIES - 1;
* #endif
*/

View file

@ -82,6 +82,7 @@
#include <xtensa/xtruntime.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>
@ -134,9 +135,9 @@
/* owner field values:
* 0 - Uninitialized (invalid)
* portMUX_FREE_VAL - Mux is free, can be locked by either CPU
* CORE_ID_PRO / CORE_ID_APP - Mux is locked to the particular core
* CORE_ID_REGVAL_PRO / CORE_ID_REGVAL_APP - Mux is locked to the particular core
*
* Any value other than portMUX_FREE_VAL, CORE_ID_PRO, CORE_ID_APP indicates corruption
* Any value other than portMUX_FREE_VAL, CORE_ID_REGVAL_PRO, CORE_ID_REGVAL_APP indicates corruption
*/
uint32_t owner;
@ -283,8 +284,11 @@
/*Because the ROM routines don't necessarily handle a stack in external RAM correctly, we force */
/*the stack memory to always be internal. */
#define pvPortMallocTcbMem( size ) heap_caps_malloc( size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT )
#define pvPortMallocStackMem( size ) heap_caps_malloc( size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT )
#define portTcbMemoryCaps (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)
#define portStackMemoryCaps (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)
#define pvPortMallocTcbMem(size) heap_caps_malloc(size, portTcbMemoryCaps)
#define pvPortMallocStackMem(size) heap_caps_malloc(size, portStackMemoryCaps)
/*xTaskCreateStatic uses these functions to check incoming memory. */
#define portVALID_TCB_MEM( ptr ) ( esp_ptr_internal( ptr ) && esp_ptr_byte_accessible( ptr ) )
@ -307,17 +311,55 @@
uint32_t compare,
uint32_t * set )
{
#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0))
__asm__ __volatile__ (
"WSR %2,SCOMPARE1 \n"
"S32C1I %0, %1, 0 \n"
: "=r" ( *set )
: "r" ( addr ), "r" ( compare ), "0" ( *set )
);
#else
#if ( XCHAL_HAVE_S32C1I > 0 )
__asm__ __volatile__ (
"WSR %2,SCOMPARE1 \n"
"S32C1I %0, %1, 0 \n"
: "=r" ( *set )
: "r" ( addr ), "r" ( compare ), "0" ( *set )
);
#else
/* No S32C1I, so do this by disabling and re-enabling interrupts (slower) */
uint32_t intlevel, old_value;
__asm__ __volatile__ ( "rsil %0, " XTSTR( XCHAL_EXCM_LEVEL ) "\n"
: "=r" ( intlevel ) );
old_value = *addr;
if( old_value == compare )
{
*addr = *set;
}
__asm__ __volatile__ ( "memw \n"
"wsr %0, ps\n"
: : "r" ( intlevel ) );
*set = old_value;
#endif /* if ( XCHAL_HAVE_S32C1I > 0 ) */
#endif /* #if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0)) */
}
#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0))
void uxPortCompareSetExtram( volatile uint32_t * addr,
uint32_t compare,
uint32_t * set );
#else
static inline void uxPortCompareSetExtram(volatile uint32_t *addr, uint32_t compare, uint32_t *set)
{
#if defined(CONFIG_ESP32_SPIRAM_SUPPORT)
compare_and_set_extram(addr, compare, set);
#endif
}
#endif
/*-----------------------------------------------------------*/
@ -389,9 +431,35 @@
#endif
bool vApplicationSleep( TickType_t xExpectedIdleTime );
void vPortSetStackWatchpoint( void* pxStackStart );
#define portSUPPRESS_TICKS_AND_SLEEP( idleTime ) vApplicationSleep( idleTime )
/*-----------------------------------------------------------*/
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0))
/* Architecture specific optimisations. */
#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
/* Check the configuration. */
#if( configMAX_PRIORITIES > 32 )
#error configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 different priorities as tasks that share a priority will time slice.
#endif
/* Store/clear the ready priorities in a bit map. */
#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )
/*-----------------------------------------------------------*/
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31 - __builtin_clz( ( uxReadyPriorities ) ) )
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0) */
/*-----------------------------------------------------------*/
void _xt_coproc_release( volatile void * coproc_sa_base );
@ -409,6 +477,7 @@
#define xPortGetFreeHeapSize esp_get_free_heap_size
#define xPortGetMinimumEverFreeHeapSize esp_get_minimum_free_heap_size
#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0))
/*
* Send an interrupt to another core in order to make the task running
* on it yield for a higher-priority task.
@ -416,6 +485,7 @@
void vPortYieldOtherCore( BaseType_t coreid ) PRIVILEGED_FUNCTION;
#endif /* ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0) */
/*
* Callback to set a watchpoint on the end of the stack. Called every context switch to change the stack
@ -429,6 +499,7 @@
*/
BaseType_t xPortInIsrContext();
/*
* 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.

View file

@ -0,0 +1,88 @@
/*
* Copyright (c) 2017, Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
/* Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* File adapted to use on IDF FreeRTOS component, extracted
* originally from zephyr RTOS code base:
* https://github.com/zephyrproject-rtos/zephyr/blob/dafd348/arch/xtensa/include/xtensa-asm2-s.h
*/
#ifndef __XT_ASM_UTILS_H
#define __XT_ASM_UTILS_H
/*
* SPILL_ALL_WINDOWS
*
* Spills all windowed registers (i.e. registers not visible as
* A0-A15) to their ABI-defined spill regions on the stack.
*
* Unlike the Xtensa HAL implementation, this code requires that the
* EXCM and WOE bit be enabled in PS, and relies on repeated hardware
* exception handling to do the register spills. The trick is to do a
* noop write to the high registers, which the hardware will trap
* (into an overflow exception) in the case where those registers are
* already used by an existing call frame. Then it rotates the window
* and repeats until all but the A0-A3 registers of the original frame
* are guaranteed to be spilled, eventually rotating back around into
* the original frame. Advantages:
*
* - Vastly smaller code size
*
* - More easily maintained if changes are needed to window over/underflow
* exception handling.
*
* - Requires no scratch registers to do its work, so can be used safely in any
* context.
*
* - If the WOE bit is not enabled (for example, in code written for
* the CALL0 ABI), this becomes a silent noop and operates compatbily.
*
* - Hilariously it's ACTUALLY FASTER than the HAL routine. And not
* just a little bit, it's MUCH faster. With a mostly full register
* file on an LX6 core (ESP-32) I'm measuring 145 cycles to spill
* registers with this vs. 279 (!) to do it with
* xthal_spill_windows().
*/
.macro SPILL_ALL_WINDOWS
#if XCHAL_NUM_AREGS == 64
and a12, a12, a12
rotw 3
and a12, a12, a12
rotw 3
and a12, a12, a12
rotw 3
and a12, a12, a12
rotw 3
and a12, a12, a12
rotw 4
#elif XCHAL_NUM_AREGS == 32
and a12, a12, a12
rotw 3
and a12, a12, a12
rotw 3
and a4, a4, a4
rotw 2
#else
#error Unrecognized XCHAL_NUM_AREGS
#endif
.endm
#endif

View file

@ -45,6 +45,7 @@ NOTE: The Xtensa architecture requires stack pointer alignment to 16 bytes.
#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. */
@ -325,8 +326,19 @@ STRUCT_END(XtSolFrame)
.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
/*
-------------------------------------------------------------------------------

View file

@ -96,16 +96,29 @@
#include <xtensa/config/core.h>
#include "xtensa_rtos.h"
#include "esp_idf_version.h"
#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0))
#include "rom/ets_sys.h"
#include "esp_panic.h"
#include "esp_crosscore_int.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
#include "esp_private/panic_reason.h"
#include "esp_debug_helpers.h"
#include "esp_private/crosscore_int.h"
#include "esp_log.h"
#endif /* ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0) */
#include "soc/cpu.h"
#include "FreeRTOS.h"
#include "task.h"
#include "esp_panic.h"
#include "esp_heap_caps.h"
#include "esp_crosscore_int.h"
#include "esp_intr_alloc.h"
@ -133,6 +146,19 @@ unsigned port_interruptNesting[ portNUM_PROCESSORS ] = { 0 }; /* Interrupt nest
/* User exception dispatcher when exiting */
void _xt_user_exit( void );
#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 /* if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER */
/*
* Stack initialization
*/
@ -168,7 +194,11 @@ void _xt_user_exit( void );
frame = ( XtExcFrame * ) sp;
/* Explicitly initialize certain saved registers */
#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 */
@ -176,13 +206,23 @@ void _xt_user_exit( void );
/* Set initial PS to int level 0, EXCM disabled ('rfe' will enable), user mode. */
/* Also set entry point argument parameter. */
#ifdef __XTENSA_CALL0_ABI__
#if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
frame->a2 = ( UBaseType_t ) pxCode;
frame->a3 = ( UBaseType_t ) pvParameters;
#else
frame->a2 = ( UBaseType_t ) pvParameters;
#endif
frame->ps = PS_UM | PS_EXCM;
#else
/* + for windowed ABI also set WOE and CALLINC (pretend task was 'call4'd). */
#if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
frame->a6 = ( UBaseType_t ) pxCode;
frame->a7 = ( UBaseType_t ) pvParameters;
#else
frame->a6 = ( UBaseType_t ) pvParameters;
frame->ps = PS_UM | PS_EXCM | PS_WOE | PS_CALLINC( 1 );
#endif
frame->ps = PS_UM | PS_EXCM | PS_WOE | PS_CALLINC( 1 );
#endif /* ifdef __XTENSA_CALL0_ABI__ */
#ifdef XT_USE_SWPRI
/* Set the initial virtual priority mask value to all 1's. */
@ -455,6 +495,8 @@ void vPortSetStackWatchpoint( void * pxStackStart )
{
uint32_t prev;
uint32_t oldlevel = portENTER_CRITICAL_NESTED();
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
vPortCPUAcquireMutexIntsDisabled( &extram_mux, portMUX_NO_TIMEOUT, __FUNCTION__, __LINE__ );
#else
@ -473,6 +515,8 @@ void vPortSetStackWatchpoint( void * pxStackStart )
#else
vPortCPUReleaseMutexIntsDisabled( &extram_mux );
#endif
portEXIT_CRITICAL_NESTED(oldlevel);
}
#endif //defined(CONFIG_SPIRAM_SUPPORT)

View file

@ -25,6 +25,7 @@
#include "xtensa_rtos.h"
#include "sdkconfig.h"
#include "esp_idf_version.h"
#define TOPOFSTACK_OFFS 0x00 /* StackType_t *pxTopOfStack */
#define CP_TOPOFSTACK_OFFS 0x04 /* xMPU_SETTINGS.coproc_area */
@ -138,8 +139,28 @@ _frxt_int_enter:
mull a2, a4, a2
add a1, a1, a2 /* for current proc */
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0))
#ifdef CONFIG_FREERTOS_FPU_IN_ISR
#if XCHAL_CP_NUM > 0
rsr a3, CPENABLE /* Restore thread scope CPENABLE */
addi sp, sp,-4 /* ISR will manage FPU coprocessor by forcing */
s32i a3, a1, 0 /* its trigger */
#endif
#endif
#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0) */
.Lnested:
1:
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0))
#ifdef CONFIG_FREERTOS_FPU_IN_ISR
#if XCHAL_CP_NUM > 0
movi a3, 0 /* whilst ISRs pending keep CPENABLE exception active */
wsr a3, CPENABLE
rsync
#endif
#endif
#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0) */
mov a0, a12 /* restore return addr and return */
ret
@ -176,6 +197,17 @@ _frxt_int_exit:
s32i a2, a3, 0 /* save nesting count */
bnez a2, .Lnesting /* !=0 after decr so still nested */
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0))
#ifdef CONFIG_FREERTOS_FPU_IN_ISR
#if XCHAL_CP_NUM > 0
l32i a3, sp, 0 /* Grab last CPENABLE before leave ISR */
addi sp, sp, 4
wsr a3, CPENABLE
rsync /* ensure CPENABLE was modified */
#endif
#endif
#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0) */
movi a2, pxCurrentTCB
addx4 a2, a4, a2
l32i a2, a2, 0 /* a2 = current TCB */
@ -642,7 +674,6 @@ _frxt_task_coproc_state:
addx4 a15, a3, a15
l32i a15, a15, 0 /* && pxCurrentTCB != 0) { */
beqz a15, 2f
l32i a15, a15, CP_TOPOFSTACK_OFFS
ret

View file

@ -48,7 +48,11 @@
#include "portable.h"
/* XOR one core ID with this value to get the other core ID */
#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0))
#define CORE_ID_XOR_SWAP ( CORE_ID_PRO ^ CORE_ID_APP )
#else
#define CORE_ID_REGVAL_XOR_SWAP (CORE_ID_REGVAL_PRO ^ CORE_ID_REGVAL_APP)
#endif

View file

@ -70,7 +70,11 @@ static inline bool __attribute__( ( always_inline ) )
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
uint32_t owner = mux->owner;
#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0))
if( ( owner != portMUX_FREE_VAL ) && ( owner != CORE_ID_PRO ) && ( owner != CORE_ID_APP ) )
#else
if (owner != portMUX_FREE_VAL && owner != CORE_ID_REGVAL_PRO && owner != CORE_ID_REGVAL_APP)
#endif
{
ets_printf( "ERROR: vPortCPUAcquireMutex: mux %p is uninitialized (0x%X)! Called from %s line %d.\n", mux, owner, fnName, line );
mux->owner = portMUX_FREE_VAL;
@ -84,7 +88,11 @@ static inline bool __attribute__( ( always_inline ) )
/* Note: coreID is the full 32 bit core ID (CORE_ID_PRO/CORE_ID_APP),
* not the 0/1 value returned by xPortGetCoreID()
*/
#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0))
otherCoreID = CORE_ID_XOR_SWAP ^ coreID;
#else
otherCoreID = CORE_ID_REGVAL_XOR_SWAP ^ coreID;
#endif
do
{
@ -163,7 +171,11 @@ static inline bool __attribute__( ( always_inline ) )
mux->lastLockedLine = line;
uint32_t owner = mux->owner;
#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0))
if( ( owner != portMUX_FREE_VAL ) && ( owner != CORE_ID_PRO ) && ( owner != CORE_ID_APP ) )
#else
if (owner != portMUX_FREE_VAL && owner != CORE_ID_REGVAL_PRO && owner != CORE_ID_REGVAL_APP)
#endif
{
ets_printf( "ERROR: vPortCPUReleaseMutex: mux %p is invalid (0x%x)!\n", mux, mux->owner );
}

View file

@ -51,6 +51,10 @@ NOERROR: .error "C preprocessor needed for this file: make sure its filename\
#include "xtensa_rtos.h"
#include "xtensa_context.h"
#include "esp_idf_version.h"
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0))
#include "xt_asm_utils.h"
#endif
#ifdef XT_USE_OVLY
#include <xtensa/overlay_os_asm.h>
@ -58,8 +62,6 @@ NOERROR: .error "C preprocessor needed for this file: make sure its filename\
.text
/*******************************************************************************
_xt_context_save
@ -97,6 +99,7 @@ Exit conditions:
.align 4
.literal_position
.align 4
_xt_context_save:
s32i a2, sp, XT_STK_A2
@ -143,6 +146,7 @@ _xt_context_save:
mov a9, a0 /* preserve ret addr */
#endif
#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0))
#ifndef __XTENSA_CALL0_ABI__
/*
To spill the reg windows, temp. need pre-interrupt stack ptr and a4-15.
@ -175,25 +179,76 @@ _xt_context_save:
l32i a13, sp, XT_STK_TMP1
l32i a9, sp, XT_STK_TMP2
#endif
#endif /* (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0)) */
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0))
s32i a12, sp, XT_STK_TMP0 /* temp. save stuff in stack frame */
s32i a13, sp, XT_STK_TMP1
s32i a9, sp, XT_STK_TMP2
l32i a12, sp, XT_STK_A12 /* recover original a9,12,13 */
l32i a13, sp, XT_STK_A13
l32i a9, sp, XT_STK_A9
#endif
#if XCHAL_EXTRA_SA_SIZE > 0
/*
NOTE: Normally the xthal_save_extra_nw macro only affects address
registers a2-a5. It is theoretically possible for Xtensa processor
designers to write TIE that causes more address registers to be
affected, but it is generally unlikely. If that ever happens,
more registers need to be saved/restored around this macro invocation.
Here we assume a9,12,13 are preserved.
Future Xtensa tools releases might limit the regs that can be affected.
*/
addi a2, sp, XT_STK_EXTRA /* where to save it */
# if XCHAL_EXTRA_SA_ALIGN > 16
movi a3, -XCHAL_EXTRA_SA_ALIGN
and a2, a2, a3 /* align dynamically >16 bytes */
# endif
call0 xthal_save_extra_nw /* destroys a0,2,3,4,5 */
call0 xthal_save_extra_nw /* destroys a0,2,3 */
#endif
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0))
#ifndef __XTENSA_CALL0_ABI__
#ifdef XT_USE_OVLY
l32i a9, sp, XT_STK_PC /* recover saved PC */
_xt_overlay_get_state a9, a12, a13
s32i a9, sp, XT_STK_OVLY /* save overlay state */
#endif
/* SPILL_ALL_WINDOWS macro requires window overflow exceptions to be enabled,
* i.e. PS.EXCM cleared and PS.WOE set.
* Since we are going to clear PS.EXCM, we also need to increase INTLEVEL
* at least to XCHAL_EXCM_LEVEL. This matches that value of effective INTLEVEL
* at entry (CINTLEVEL=max(PS.INTLEVEL, XCHAL_EXCM_LEVEL) when PS.EXCM is set.
* Since WindowOverflow exceptions will trigger inside SPILL_ALL_WINDOWS,
* need to save/restore EPC1 as well.
* Note: even though a4-a15 are saved into the exception frame, we should not
* clobber them until after SPILL_ALL_WINDOWS. This is because these registers
* may contain live windows belonging to previous frames in the call stack.
* These frames will be spilled by SPILL_ALL_WINDOWS, and if the register was
* used as a temporary by this code, the temporary value would get stored
* onto the stack, instead of the real value.
*/
rsr a2, PS /* to be restored after SPILL_ALL_WINDOWS */
movi a0, PS_INTLEVEL_MASK
and a3, a2, a0 /* get the current INTLEVEL */
bgeui a3, XCHAL_EXCM_LEVEL, 1f /* calculate max(INTLEVEL, XCHAL_EXCM_LEVEL) */
movi a3, XCHAL_EXCM_LEVEL
1:
movi a0, PS_UM | PS_WOE /* clear EXCM, enable window overflow, set new INTLEVEL */
or a3, a3, a0
wsr a3, ps
rsr a0, EPC1 /* to be restored after SPILL_ALL_WINDOWS */
addi sp, sp, XT_STK_FRMSZ /* restore the interruptee's SP */
SPILL_ALL_WINDOWS
addi sp, sp, -XT_STK_FRMSZ /* return the current stack pointer and proceed with context save*/
wsr a2, PS /* restore to the value at entry */
rsync
wsr a0, EPC1 /* likewise */
#endif /* __XTENSA_CALL0_ABI__ */
l32i a12, sp, XT_STK_TMP0 /* restore the temp saved registers */
l32i a13, sp, XT_STK_TMP1 /* our return address is there */
l32i a9, sp, XT_STK_TMP2
#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0) */
#if XCHAL_EXTRA_SA_SIZE > 0 || !defined(__XTENSA_CALL0_ABI__)
mov a0, a9 /* retrieve ret addr */
#endif

View file

@ -34,7 +34,16 @@
#endif
#include "xtensa_rtos.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"
#endif
#endif /* ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0) */
#ifdef XT_RTOS_TIMER_INT

View file

@ -33,8 +33,17 @@
#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

View file

@ -13,7 +13,12 @@
// limitations under the License.
#include "xtensa_rtos.h"
#include "esp_idf_version.h"
#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0))
#include "esp_panic.h"
#else
#include "esp_private/panic_reason.h"
#endif /* ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0) */
#include "sdkconfig.h"
#include "soc/soc.h"

View file

@ -91,10 +91,14 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*******************************************************************************/
#include "xtensa_rtos.h"
#include "esp_idf_version.h"
#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0))
#include "esp_panic.h"
#else
#include "esp_private/panic_reason.h"
#endif /* ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0) */
#include "sdkconfig.h"
#include "soc/soc.h"
#include "soc/dport_reg.h"
/*
Define for workaround: pin no-cpu-affinity tasks to a cpu when fpu is used.
@ -103,7 +107,25 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define TASKTCB_XCOREID_OFFSET (0x38+configMAX_TASK_NAME_LEN+3)&~3
.extern pxCurrentTCB
/* Enable stack backtrace across exception/interrupt - see below */
/*
--------------------------------------------------------------------------------
In order for backtracing to be able to trace from the pre-exception stack
across to the exception stack (including nested interrupts), we need to create
a pseudo base-save area to make it appear like the exception dispatcher was
triggered by a CALL4 from the pre-exception code. In reality, the exception
dispatcher uses the same window as pre-exception code, and only CALL0s are
used within the exception dispatcher.
To create the pseudo base-save area, we need to store a copy of the pre-exception's
base save area (a0 to a4) below the exception dispatcher's SP. EXCSAVE_x will
be used to store a copy of the SP that points to the interrupted code's exception
frame just in case the exception dispatcher's SP does not point to the exception
frame (which is the case when switching from task to interrupt stack).
Clearing the pseudo base-save area is uncessary as the interrupt dispatcher
will restore the current SP to that of the pre-exception SP.
--------------------------------------------------------------------------------
*/
#ifdef CONFIG_FREERTOS_INTERRUPT_BACKTRACE
#define XT_DEBUG_BACKTRACE 1
#endif
@ -202,9 +224,24 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/* This bit of code provides a nice debug backtrace in the debugger.
It does take a few more instructions, so undef XT_DEBUG_BACKTRACE
if you want to save the cycles.
At this point, the exception frame should have been allocated and filled,
and current sp points to the interrupt stack (for non-nested interrupt)
or below the allocated exception frame (for nested interrupts). Copy the
pre-exception's base save area below the current SP.
*/
#ifdef XT_DEBUG_BACKTRACE
#ifndef __XTENSA_CALL0_ABI__
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0))
rsr a0, EXCSAVE_1 + \level - 1 /* Get exception frame pointer stored in EXCSAVE_x */
l32i a3, a0, XT_STK_A0 /* Copy pre-exception a0 (return address) */
s32e a3, a1, -16
l32i a3, a0, XT_STK_A1 /* Copy pre-exception a1 (stack pointer) */
s32e a3, a1, -12
#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0) */
/* Backtracing only needs a0 and a1, no need to create full base save area.
Also need to change current frame's return address to point to pre-exception's
last run instruction.
*/
rsr a0, EPC_1 + \level - 1 /* return address */
movi a4, 0xC0000000 /* constant with top 2 bits set (call size) */
or a0, a0, a4 /* set top 2 bits */
@ -698,8 +735,18 @@ _xt_user_exc:
#endif
wsr a0, PS
/*
Create pseudo base save area. At this point, sp is still pointing to the
allocated and filled exception stack frame.
*/
#ifdef XT_DEBUG_BACKTRACE
#ifndef __XTENSA_CALL0_ABI__
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0))
l32i a3, sp, XT_STK_A0 /* Copy pre-exception a0 (return address) */
s32e a3, sp, -16
l32i a3, sp, XT_STK_A1 /* Copy pre-exception a1 (stack pointer) */
s32e a3, sp, -12
#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0) */
rsr a0, EPC_1 /* return address for debug backtrace */
movi a5, 0xC0000000 /* constant with top 2 bits set (call size) */
rsync /* wait for WSR.PS to complete */
@ -945,7 +992,15 @@ _xt_coproc_exc:
/* Get co-processor state save area of new owner thread. */
call0 XT_RTOS_CP_STATE /* a15 = new owner's save area */
#if (ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0))
beqz a15, .L_goto_invalid /* not in a thread (invalid) */
#else
#ifndef CONFIG_FREERTOS_FPU_IN_ISR
beqz a15, .L_goto_invalid
#endif
#endif /* ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 2, 0) */
/*When FPU in ISR is enabled we could deal with zeroed a15 */
/* Enable the co-processor's bit in CPENABLE. */
movi a0, _xt_coproc_mask
@ -987,7 +1042,17 @@ locking.
rsync /* ensure wsr.CPENABLE is complete */
/* Only need to context switch if new owner != old owner. */
/* If float is necessary on ISR, we need to remove this check */
/* below, because on restoring from ISR we may have new == old condition used
* to force cp restore to next thread
*/
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0))
#ifndef CONFIG_FREERTOS_FPU_IN_ISR
#endif
beq a15, a2, .L_goto_done /* new owner == old, we're done */
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0))
#endif
#endif
/* If no old owner then nothing to save. */
beqz a2, .L_check_new
@ -1029,6 +1094,9 @@ locking.
.L_check_new:
/* Check if any state has to be restored for new owner. */
/* NOTE: a15 = new owner's save area, cannot be zero when we get here. */
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0))
beqz a15, .L_xt_coproc_done
#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0) */
l16ui a3, a15, XT_CPSTORED /* a3 = new owner's CPSTORED */
movi a4, _xt_coproc_sa_offset
@ -1114,6 +1182,18 @@ _xt_lowint1:
movi a0, _xt_user_exit /* save exit point for dispatch */
s32i a0, sp, XT_STK_EXIT
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0))
/* EXCSAVE_1 should now be free to use. Use it to keep a copy of the
current stack pointer that points to the exception frame (XT_STK_FRAME).*/
#ifdef XT_DEBUG_BACKTRACE
#ifndef __XTENSA_CALL0_ABI__
mov a0, sp
wsr a0, EXCSAVE_1
#endif
#endif
#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0) */
/* Save rest of interrupt context and enter RTOS. */
call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */
@ -1194,6 +1274,18 @@ _xt_medint2:
movi a0, _xt_medint2_exit /* save exit point for dispatch */
s32i a0, sp, XT_STK_EXIT
/* EXCSAVE_2 should now be free to use. Use it to keep a copy of the
current stack pointer that points to the exception frame (XT_STK_FRAME).*/
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0))
#ifdef XT_DEBUG_BACKTRACE
#ifndef __XTENSA_CALL0_ABI__
mov a0, sp
wsr a0, EXCSAVE_2
#endif
#endif
#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0) */
/* Save rest of interrupt context and enter RTOS. */
call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */
@ -1265,6 +1357,18 @@ _xt_medint3:
movi a0, _xt_medint3_exit /* save exit point for dispatch */
s32i a0, sp, XT_STK_EXIT
/* EXCSAVE_3 should now be free to use. Use it to keep a copy of the
current stack pointer that points to the exception frame (XT_STK_FRAME).*/
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0))
#ifdef XT_DEBUG_BACKTRACE
#ifndef __XTENSA_CALL0_ABI__
mov a0, sp
wsr a0, EXCSAVE_3
#endif
#endif
#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0) */
/* Save rest of interrupt context and enter RTOS. */
call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */
@ -1335,6 +1439,18 @@ _xt_medint4:
movi a0, _xt_medint4_exit /* save exit point for dispatch */
s32i a0, sp, XT_STK_EXIT
/* EXCSAVE_4 should now be free to use. Use it to keep a copy of the
current stack pointer that points to the exception frame (XT_STK_FRAME).*/
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0))
#ifdef XT_DEBUG_BACKTRACE
#ifndef __XTENSA_CALL0_ABI__
mov a0, sp
wsr a0, EXCSAVE_4
#endif
#endif
#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0) */
/* Save rest of interrupt context and enter RTOS. */
call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */
@ -1405,6 +1521,17 @@ _xt_medint5:
movi a0, _xt_medint5_exit /* save exit point for dispatch */
s32i a0, sp, XT_STK_EXIT
/* EXCSAVE_5 should now be free to use. Use it to keep a copy of the
current stack pointer that points to the exception frame (XT_STK_FRAME).*/
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0))
#ifdef XT_DEBUG_BACKTRACE
#ifndef __XTENSA_CALL0_ABI__
mov a0, sp
wsr a0, EXCSAVE_5
#endif
#endif
#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0) */
/* Save rest of interrupt context and enter RTOS. */
call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */
@ -1475,6 +1602,17 @@ _xt_medint6:
movi a0, _xt_medint6_exit /* save exit point for dispatch */
s32i a0, sp, XT_STK_EXIT
/* EXCSAVE_6 should now be free to use. Use it to keep a copy of the
current stack pointer that points to the exception frame (XT_STK_FRAME).*/
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0))
#ifdef XT_DEBUG_BACKTRACE
#ifndef __XTENSA_CALL0_ABI__
mov a0, sp
wsr a0, EXCSAVE_6
#endif
#endif
#endif /* ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0) */
/* Save rest of interrupt context and enter RTOS. */
call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */