From 89dd2fe7f5d6e0f1b8ea5b0b4312a370c5aa9217 Mon Sep 17 00:00:00 2001 From: Darian Leung Date: Thu, 24 Feb 2022 20:33:24 +0800 Subject: [PATCH] freertos: Copy IDF xtensa port files This commit copies over ESP-IDF Xtensa portable files to the FreeRTOS-Kernel-SMP directory. No changes were made, this commit only copies the portable source files. Notes: - This commit WILL NOT compile - Some SPDX header dates were updated to pass pre-commit check --- .../xtensa/include/freertos/portbenchmark.h | 52 + .../xtensa/include/freertos/portmacro.h | 776 +++++++ .../include/freertos/portmacro_deprecated.h | 93 + .../xtensa/include/freertos/xtensa_api.h | 2 + .../xtensa/include/freertos/xtensa_config.h | 188 ++ .../xtensa/include/freertos/xtensa_context.h | 2 + .../xtensa/include/freertos/xtensa_rtos.h | 241 ++ .../xtensa/include/freertos/xtensa_timer.h | 165 ++ .../portable/xtensa/port.c | 484 ++++ .../portable/xtensa/portasm.S | 679 ++++++ .../portable/xtensa/readme_xtensa.txt | 763 +++++++ .../portable/xtensa/xt_asm_utils.h | 75 + .../portable/xtensa/xtensa_context.S | 665 ++++++ .../portable/xtensa/xtensa_init.c | 62 + .../xtensa/xtensa_loadstore_handler.S | 549 +++++ .../portable/xtensa/xtensa_overlay_os_hook.c | 77 + .../portable/xtensa/xtensa_vector_defaults.S | 230 ++ .../portable/xtensa/xtensa_vectors.S | 1945 +++++++++++++++++ 18 files changed, 7048 insertions(+) create mode 100644 components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/portbenchmark.h create mode 100644 components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/portmacro.h create mode 100644 components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/portmacro_deprecated.h create mode 100644 components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/xtensa_api.h create mode 100644 components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/xtensa_config.h create mode 100644 components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/xtensa_context.h create mode 100644 components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/xtensa_rtos.h create mode 100644 components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/xtensa_timer.h create mode 100644 components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c create mode 100644 components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/portasm.S create mode 100644 components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/readme_xtensa.txt create mode 100644 components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/xt_asm_utils.h create mode 100644 components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/xtensa_context.S create mode 100644 components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/xtensa_init.c create mode 100644 components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/xtensa_loadstore_handler.S create mode 100644 components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/xtensa_overlay_os_hook.c create mode 100644 components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/xtensa_vector_defaults.S create mode 100644 components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/xtensa_vectors.S diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/portbenchmark.h b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/portbenchmark.h new file mode 100644 index 0000000000..69913f28f3 --- /dev/null +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/portbenchmark.h @@ -0,0 +1,52 @@ +/* + * 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. + */ + +/* + * This utility helps benchmarking interrupt latency and context switches. + * In order to enable it, set configBENCHMARK to 1 in FreeRTOSConfig.h. + * You will also need to download the FreeRTOS_trace patch that contains + * portbenchmark.c and the complete version of portbenchmark.h + */ + +#ifndef PORTBENCHMARK_H +#define PORTBENCHMARK_H + +#if configBENCHMARK + #error "You need to download the FreeRTOS_trace patch that overwrites this file" +#endif + +#define portbenchmarkINTERRUPT_DISABLE() +#define portbenchmarkINTERRUPT_RESTORE(newstate) +#define portbenchmarkIntLatency() +#define portbenchmarkIntWait() +#define portbenchmarkReset() +#define portbenchmarkPrint() + +#endif /* PORTBENCHMARK */ diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/portmacro.h b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/portmacro.h new file mode 100644 index 0000000000..b016f8c9df --- /dev/null +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/portmacro.h @@ -0,0 +1,776 @@ +/* + * SPDX-FileCopyrightText: 2017 Amazon.com, Inc. or its affiliates + * SPDX-FileCopyrightText: 2015-2019 Cadence Design Systems, Inc. + * + * 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! + */ + +/* + * 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. + */ + +#ifndef PORTMACRO_H +#define PORTMACRO_H + +#ifndef __ASSEMBLER__ + +#include "sdkconfig.h" +#include +#include +#include +#include +#include +#include /* required for xthal_get_ccount. [refactor-todo] use cpu_hal instead */ +#include /* required for XTOS_SET_INTLEVEL. [refactor-todo] add common intr functions to esp_hw_support */ +#include "xt_instr_macros.h" +#include "soc/spinlock.h" +#include "hal/cpu_hal.h" +#include "esp_private/crosscore_int.h" +#include "esp_macro.h" +#include "esp_attr.h" +#include "esp_timer.h" /* required for esp_timer_get_time. [refactor-todo] make this common between archs */ +#include "esp_newlib.h" /* required for esp_reent_init() in tasks.c */ +#include "esp_heap_caps.h" +#include "esp_rom_sys.h" +#include "esp_system.h" /* required by esp_get_...() functions in portable.h. [refactor-todo] Update portable.h */ +#include "portbenchmark.h" + +/* [refactor-todo] These includes are not directly used in this file. They are kept into to prevent a breaking change. Remove these. */ +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* --------------------------------------------------- Port Types ------------------------------------------------------ + * - Port specific types. + * - The settings in this file configure FreeRTOS correctly for the given hardware and compiler. + * - These settings should not be altered. + * - The port types must come before first as they are used further down the file + * ------------------------------------------------------------------------------------------------------------------ */ + +#define portCHAR int8_t +#define portFLOAT float +#define portDOUBLE double +#define portLONG int32_t +#define portSHORT int16_t +#define portSTACK_TYPE uint8_t +#define portBASE_TYPE int + +typedef portSTACK_TYPE StackType_t; +typedef portBASE_TYPE BaseType_t; +typedef unsigned portBASE_TYPE UBaseType_t; + +#if( configUSE_16_BIT_TICKS == 1 ) +typedef uint16_t TickType_t; +#define portMAX_DELAY ( TickType_t ) 0xffff +#else +typedef uint32_t TickType_t; +#define portMAX_DELAY ( TickType_t ) 0xffffffffUL +#endif + +/* Task function macros as described on the FreeRTOS.org WEB site. */ +#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters ) +#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters ) + + + +/* ----------------------------------------------- Port Configurations ------------------------------------------------- + * - Configurations values supplied by each port + * - Required by FreeRTOS + * ------------------------------------------------------------------------------------------------------------------ */ + +#define portCRITICAL_NESTING_IN_TCB 0 +#define portSTACK_GROWTH ( -1 ) +#define portTICK_PERIOD_MS ( ( TickType_t ) 1000 / configTICK_RATE_HZ ) +#define portBYTE_ALIGNMENT 4 +#define portNOP() XT_NOP() + + + +/* ---------------------------------------------- Forward Declarations ------------------------------------------------- + * - Forward declarations of all the port functions and macros need to implement the FreeRTOS porting interface + * - These must come before definition/declaration of the FreeRTOS porting interface + * ------------------------------------------------------------------------------------------------------------------ */ + +// --------------------- Interrupts ------------------------ + +/** + * @brief Checks if the current core is in an ISR context + * + * - ISR context consist of Low/Mid priority ISR, or time tick ISR + * - High priority ISRs aren't detected here, but they normally cannot call C code, so that should not be an issue anyway. + * + * @note [refactor-todo] Check if this should be inlined + * @return + * - pdTRUE if in ISR + * - pdFALSE otherwise + */ +BaseType_t xPortInIsrContext(void); + +/** + * @brief Asserts if in ISR context + * + * - Asserts on xPortInIsrContext() internally + * + * @note [refactor-todo] Check if this API is still required + * @note [refactor-todo] Check if this should be inlined + */ +void vPortAssertIfInISR(void); + +/** + * @brief Check if in ISR context from High priority ISRs + * + * - Called from High priority ISR + * - Checks if the previous context (before high priority interrupt) was in ISR context (meaning low/med priority) + * + * @note [refactor-todo] Check if this should be inlined + * @return + * - pdTRUE if in previous in ISR context + * - pdFALSE otherwise + */ +BaseType_t xPortInterruptedFromISRContext(void); + +/** + * @brief Disable interrupts in a nested manner (meant to be called from ISRs) + * + * @warning Only applies to current CPU. + * @return UBaseType_t Previous interrupt level + */ +static inline UBaseType_t xPortSetInterruptMaskFromISR(void); + +/** + * @brief Reenable interrupts in a nested manner (meant to be called from ISRs) + * + * @warning Only applies to current CPU. + * @param prev_level Previous interrupt level + */ +static inline void vPortClearInterruptMaskFromISR(UBaseType_t prev_level); + +/* ---------------------- Spinlocks ------------------------ + * - Modifications made to critical sections to support SMP + * - See "Critical Sections & Disabling Interrupts" in docs/api-guides/freertos-smp.rst for more details + * - 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 + * behaviorr; please keep this in mind if you need any compatibility with other FreeRTOS implementations. + * @note [refactor-todo] Check if these comments are still true + * ------------------------------------------------------ */ + +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 */ + +// ------------------ Critical Sections -------------------- + +/** + * @brief Enter a SMP critical section with a timeout + * + * This function enters an SMP critical section by disabling interrupts then + * taking a spinlock with a specified timeout. + * + * This function can be called in a nested manner. + * + * @note This function is made non-inline on purpose to reduce code size + * @param mux Spinlock + * @param timeout Timeout to wait for spinlock in number of CPU cycles. + * Use portMUX_NO_TIMEOUT to wait indefinitely + * Use portMUX_TRY_LOCK to only getting the spinlock a single time + * @retval pdPASS Critical section entered (spinlock taken) + * @retval pdFAIL If timed out waiting for spinlock (will not occur if using portMUX_NO_TIMEOUT) + */ +BaseType_t xPortEnterCriticalTimeout(portMUX_TYPE *mux, BaseType_t timeout); + +/** + * @brief Enter a SMP critical section + * + * This function enters an SMP critical section by disabling interrupts then + * taking a spinlock with an unlimited timeout. + * + * This function can be called in a nested manner + * + * @param[in] mux Spinlock + */ +static inline void __attribute__((always_inline)) vPortEnterCritical(portMUX_TYPE *mux); + +/** + * @brief Exit a SMP critical section + * + * This function can be called in a nested manner. On the outer most level of nesting, this function will: + * + * - Release the spinlock + * - Restore the previous interrupt level before the critical section was entered + * + * If still nesting, this function simply decrements a critical nesting count + * + * @note This function is made non-inline on purpose to reduce code size + * @param[in] mux Spinlock + */ +void vPortExitCritical(portMUX_TYPE *mux); + +/** + * @brief FreeRTOS Compliant version of xPortEnterCriticalTimeout() + * + * Compliant version of xPortEnterCriticalTimeout() will ensure that this is + * called from a task context only. An abort is called otherwise. + * + * @note This function is made non-inline on purpose to reduce code size + * + * @param mux Spinlock + * @param timeout Timeout + * @return BaseType_t + */ +BaseType_t xPortEnterCriticalTimeoutCompliance(portMUX_TYPE *mux, BaseType_t timeout); + +/** + * @brief FreeRTOS compliant version of vPortEnterCritical() + * + * Compliant version of vPortEnterCritical() will ensure that this is + * called from a task context only. An abort is called otherwise. + * + * @param[in] mux Spinlock + */ +static inline void __attribute__((always_inline)) vPortEnterCriticalCompliance(portMUX_TYPE *mux); + +/** + * @brief FreeRTOS compliant version of vPortExitCritical() + * + * Compliant version of vPortExitCritical() will ensure that this is + * called from a task context only. An abort is called otherwise. + * + * @note This function is made non-inline on purpose to reduce code size + * @param[in] mux Spinlock + */ +void vPortExitCriticalCompliance(portMUX_TYPE *mux); + +/** + * @brief Safe version of enter critical timeout + * + * Safe version of enter critical will automatically select between + * portTRY_ENTER_CRITICAL() and portTRY_ENTER_CRITICAL_ISR() + * + * @param mux Spinlock + * @param timeout Timeout + * @return BaseType_t + */ +static inline BaseType_t __attribute__((always_inline)) xPortEnterCriticalTimeoutSafe(portMUX_TYPE *mux, BaseType_t timeout); + +/** + * @brief Safe version of enter critical + * + * Safe version of enter critical will automatically select between + * portENTER_CRITICAL() and portENTER_CRITICAL_ISR() + * + * @param[in] mux Spinlock + */ +static inline void __attribute__((always_inline)) vPortEnterCriticalSafe(portMUX_TYPE *mux); + +/** + * @brief Safe version of exit critical + * + * Safe version of enter critical will automatically select between + * portEXIT_CRITICAL() and portEXIT_CRITICAL_ISR() + * + * @param[in] mux Spinlock + */ +static inline void __attribute__((always_inline)) vPortExitCriticalSafe(portMUX_TYPE *mux); + +// ---------------------- Yielding ------------------------- + +/** + * @brief Perform a solicited context switch + * + * - Defined in portasm.S + * + * @note [refactor-todo] The rest of ESP-IDF should call taskYield() instead + */ +void vPortYield( void ); + +/** + * @brief Yields the other core + * + * - Send an interrupt to another core in order to make the task running on it yield for a higher-priority task. + * - Can be used to yield current core as well + * + * @note [refactor-todo] Put this into private macros as its only called from task.c and is not public API + * @param coreid ID of core to yield + */ +void vPortYieldOtherCore(BaseType_t coreid); + +/** + * @brief Checks if the current core can yield + * + * - A core cannot yield if its in an ISR or in a critical section + * + * @note [refactor-todo] See if this can be separated from port macro + * @return true Core can yield + * @return false Core cannot yield + */ +static inline bool IRAM_ATTR xPortCanYield(void); + +// ------------------- Hook Functions ---------------------- + +/** + * @brief Hook function called on entry to tickless idle + * + * - Implemented in pm_impl.c + * + * @param xExpectedIdleTime Expected idle time + */ +void vApplicationSleep(TickType_t xExpectedIdleTime); + +// ----------------------- System -------------------------- + +/** + * @brief Get the tick rate per second + * + * @note [refactor-todo] make this inline + * @return uint32_t Tick rate in Hz + */ +uint32_t xPortGetTickRateHz(void); + +/** + * @brief Set a watchpoint to watch the last 32 bytes of the stack + * + * Callback to set a watchpoint on the end of the stack. Called every context switch to change the stack watchpoint + * around. + * + * @param pxStackStart Pointer to the start of the stack + */ +void vPortSetStackWatchpoint( void *pxStackStart ); + +/** + * @brief Get the current core's ID + * + * @note [refactor-todo] IDF should call a FreeRTOS like macro instead of port function directly + * @return BaseType_t Core ID + */ +static inline BaseType_t IRAM_ATTR xPortGetCoreID(void); + +/** + * @brief Wrapper for atomic compare-and-set instruction + * + * This subroutine will atomically compare *addr to 'compare'. If *addr == compare, *addr is set to *set. *set is + * updated with the previous value of *addr (either 'compare' or some other value.) + * + * @warning From the ISA docs: in some (unspecified) cases, the s32c1i instruction may return the "bitwise inverse" of + * the old mem if the mem wasn't written. This doesn't seem to happen on the ESP32 (portMUX assertions would + * fail). + * + * @note [refactor-todo] Check if this can be deprecated + * @note [refactor-todo] Check if this function should be renamed (due to void return type) + * + * @param[inout] addr Pointer to target address + * @param[in] compare Compare value + * @param[inout] set Pointer to set value + */ +static inline void __attribute__((always_inline)) uxPortCompareSet(volatile uint32_t *addr, uint32_t compare, uint32_t *set); + +/** + * @brief Wrapper for atomic compare-and-set instruction in external RAM + * + * Atomic compare-and-set but the target address is placed in external RAM + * + * @note [refactor-todo] Check if this can be deprecated + * + * @param[inout] addr Pointer to target address + * @param[in] compare Compare value + * @param[inout] set Pointer to set value + */ +static inline void __attribute__((always_inline)) uxPortCompareSetExtram(volatile uint32_t *addr, uint32_t compare, uint32_t *set); + + + +/* ------------------------------------------- FreeRTOS Porting Interface ---------------------------------------------- + * - Contains all the mappings of the macros required by FreeRTOS + * - Most come after forward declare as porting macros map to declared functions + * - Maps to forward declared functions + * ------------------------------------------------------------------------------------------------------------------ */ + +// ----------------------- Memory -------------------------- + +/** + * @brief Task memory allocation macros + * + * @note Because the ROM routines don't necessarily handle a stack in external RAM correctly, we force the stack + * memory to always be internal. + * @note [refactor-todo] Update portable.h to match v10.4.3 to use new malloc prototypes + */ +#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) + +// --------------------- Interrupts ------------------------ + +/** + * - Only applies to current core + * - These cannot be nested. They should be used with a lot of care and cannot be called from interrupt level. + * + * @note [refactor-todo] replace XTOS_SET_INTLEVEL with more efficient version, if any? + */ +#define portDISABLE_INTERRUPTS() do { XTOS_SET_INTLEVEL(XCHAL_EXCM_LEVEL); portbenchmarkINTERRUPT_DISABLE(); } while (0) +#define portENABLE_INTERRUPTS() do { portbenchmarkINTERRUPT_RESTORE(0); XTOS_SET_INTLEVEL(0); } while (0) + +/** + * ISR versions to enable/disable interrupts + */ +#define portSET_INTERRUPT_MASK_FROM_ISR() xPortSetInterruptMaskFromISR() +#define portCLEAR_INTERRUPT_MASK_FROM_ISR(prev_level) vPortClearInterruptMaskFromISR(prev_level) + +#define portASSERT_IF_IN_ISR() vPortAssertIfInISR() + +// ------------------ Critical Sections -------------------- + +/** + * @brief FreeRTOS critical section macros + * + * - Added a spinlock argument for SMP + * - Can be nested + * - Compliance versions will assert if regular critical section API is used in ISR context + * - Safe versions can be called from either contexts + */ +#ifdef CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE +#define portTRY_ENTER_CRITICAL(mux, timeout) xPortEnterCriticalTimeoutCompliance(mux, timeout) +#define portENTER_CRITICAL(mux) vPortEnterCriticalCompliance(mux) +#define portEXIT_CRITICAL(mux) vPortExitCriticalCompliance(mux) +#else +#define portTRY_ENTER_CRITICAL(mux, timeout) xPortEnterCriticalTimeout(mux, timeout) +#define portENTER_CRITICAL(mux) vPortEnterCritical(mux) +#define portEXIT_CRITICAL(mux) vPortExitCritical(mux) +#endif /* CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE */ + +#define portTRY_ENTER_CRITICAL_ISR(mux, timeout) xPortEnterCriticalTimeout(mux, timeout) +#define portENTER_CRITICAL_ISR(mux) vPortEnterCritical(mux) +#define portEXIT_CRITICAL_ISR(mux) vPortExitCritical(mux) + +#define portTRY_ENTER_CRITICAL_SAFE(mux, timeout) xPortEnterCriticalTimeoutSafe(mux) +#define portENTER_CRITICAL_SAFE(mux) vPortEnterCriticalSafe(mux) +#define portEXIT_CRITICAL_SAFE(mux) vPortExitCriticalSafe(mux) + +// ---------------------- Yielding ------------------------- + +#define portYIELD() vPortYield() + +extern void _frxt_setup_switch( void ); //Defined in portasm.S + +#define portYIELD_FROM_ISR_NO_ARG() ({ \ + traceISR_EXIT_TO_SCHEDULER(); \ + _frxt_setup_switch(); \ +}) +#define portYIELD_FROM_ISR_ARG(xHigherPriorityTaskWoken) ({ \ + if (xHigherPriorityTaskWoken == pdTRUE) { \ + traceISR_EXIT_TO_SCHEDULER(); \ + _frxt_setup_switch(); \ + } \ +}) + +/** + * @note 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 behavior + */ +#if defined(__cplusplus) && (__cplusplus > 201703L) +#define portYIELD_FROM_ISR(...) CHOOSE_MACRO_VA_ARG(_0 __VA_OPT__(,) ##__VA_ARGS__, portYIELD_FROM_ISR_ARG, portYIELD_FROM_ISR_NO_ARG)(__VA_ARGS__) +#else +#define portYIELD_FROM_ISR(...) CHOOSE_MACRO_VA_ARG(_0, ##__VA_ARGS__, portYIELD_FROM_ISR_ARG, portYIELD_FROM_ISR_NO_ARG)(__VA_ARGS__) +#endif + +/* Yielding within an API call (when interrupts are off), means the yield should be delayed + until interrupts are re-enabled. + + To do this, we use the "cross-core" interrupt as a trigger to yield on this core when interrupts are re-enabled.This + is the same interrupt & code path which is used to trigger a yield between CPUs, although in this case the yield is + happening on the same CPU. +*/ +#define portYIELD_WITHIN_API() esp_crosscore_int_send_yield(xPortGetCoreID()) + +// ------------------- Hook Functions ---------------------- + +#define portSUPPRESS_TICKS_AND_SLEEP(idleTime) vApplicationSleep(idleTime) + +// ------------------- Run Time Stats ---------------------- + +#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() + +/** + * - Fine resolution uses ccount + * - ALT is coarse and uses esp_timer + * @note [refactor-todo] Make fine and alt timers mutually exclusive + */ +#define portGET_RUN_TIME_COUNTER_VALUE() xthal_get_ccount() +#ifdef CONFIG_FREERTOS_RUN_TIME_STATS_USING_ESP_TIMER +#define portALT_GET_RUN_TIME_COUNTER_VALUE(x) do {x = (uint32_t)esp_timer_get_time();} while(0) +#endif + +// -------------- Optimized Task Selection ----------------- + +#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 */ + + + +/* --------------------------------------------- Inline Implementations ------------------------------------------------ + * - Implementation of inline functions of the forward declares + * - Should come after forward declare and FreeRTOS Porting interface, as implementation may use both. + * - For implementation of non-inlined functions, see port.c + * ------------------------------------------------------------------------------------------------------------------ */ + +// --------------------- Interrupts ------------------------ + +static inline UBaseType_t __attribute__((always_inline)) xPortSetInterruptMaskFromISR(void) +{ + UBaseType_t prev_int_level = XTOS_SET_INTLEVEL(XCHAL_EXCM_LEVEL); + portbenchmarkINTERRUPT_DISABLE(); + return prev_int_level; +} + +static inline void __attribute__((always_inline)) vPortClearInterruptMaskFromISR(UBaseType_t prev_level) +{ + portbenchmarkINTERRUPT_RESTORE(prev_level); + XTOS_RESTORE_JUST_INTLEVEL((int) prev_level); +} + +// ------------------ Critical Sections -------------------- + +static inline void __attribute__((always_inline)) vPortEnterCritical(portMUX_TYPE *mux) +{ + xPortEnterCriticalTimeout(mux, portMUX_NO_TIMEOUT); +} + +static inline void __attribute__((always_inline)) vPortEnterCriticalCompliance(portMUX_TYPE *mux) +{ + xPortEnterCriticalTimeoutCompliance(mux, portMUX_NO_TIMEOUT); +} + +static inline BaseType_t __attribute__((always_inline)) xPortEnterCriticalTimeoutSafe(portMUX_TYPE *mux, BaseType_t timeout) +{ + BaseType_t ret; + if (xPortInIsrContext()) { + ret = portTRY_ENTER_CRITICAL_ISR(mux, timeout); + } else { + ret = portTRY_ENTER_CRITICAL(mux, timeout); + } + return ret; +} + +static inline void __attribute__((always_inline)) vPortEnterCriticalSafe(portMUX_TYPE *mux) +{ + xPortEnterCriticalTimeoutSafe(mux, portMUX_NO_TIMEOUT); +} + +static inline void __attribute__((always_inline)) vPortExitCriticalSafe(portMUX_TYPE *mux) +{ + if (xPortInIsrContext()) { + portEXIT_CRITICAL_ISR(mux); + } else { + portEXIT_CRITICAL(mux); + } +} + +// ---------------------- Yielding ------------------------- + +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); +} + +// ----------------------- System -------------------------- + +static inline BaseType_t IRAM_ATTR xPortGetCoreID(void) +{ + return (BaseType_t) cpu_hal_get_core_id(); +} + +static inline void __attribute__((always_inline)) uxPortCompareSet(volatile uint32_t *addr, uint32_t compare, uint32_t *set) +{ + compare_and_set_native(addr, compare, set); +} + +static inline void __attribute__((always_inline)) uxPortCompareSetExtram(volatile uint32_t *addr, uint32_t compare, uint32_t *set) +{ +#ifdef CONFIG_SPIRAM + compare_and_set_extram(addr, compare, set); +#endif +} + + + +/* ------------------------------------------------------ Misc --------------------------------------------------------- + * - Miscellaneous porting macros + * - These are not port of the FreeRTOS porting interface, but are used by other FreeRTOS dependent components + * - [refactor-todo] Remove dependency on MPU wrappers by modifying TCB + * ------------------------------------------------------------------------------------------------------------------ */ + +// -------------------- Co-Processor ----------------------- + +// When coprocessors are defined, we maintain a pointer to coprocessors area. +// We currently use a hack: redefine field xMPU_SETTINGS in TCB block as a structure that can hold: +// MPU wrappers, coprocessor area pointer, trace code structure, and more if needed. +// The field is normally used for memory protection. FreeRTOS should create another general purpose field. +typedef struct { +#if XCHAL_CP_NUM > 0 + volatile StackType_t *coproc_area; // Pointer to coprocessor save area; MUST BE FIRST +#endif + +#if portUSING_MPU_WRAPPERS + // Define here mpu_settings, which is port dependent + int mpu_setting; // Just a dummy example here; MPU not ported to Xtensa yet +#endif +} xMPU_SETTINGS; + +// Main hack to use MPU_wrappers even when no MPU is defined (warning: mpu_setting should not be accessed; otherwise move this above xMPU_SETTINGS) +#if (XCHAL_CP_NUM > 0) && !portUSING_MPU_WRAPPERS // If MPU wrappers not used, we still need to allocate coproc area +#undef portUSING_MPU_WRAPPERS +#define portUSING_MPU_WRAPPERS 1 // Enable it to allocate coproc area +#define MPU_WRAPPERS_H // Override mpu_wrapper.h to disable unwanted code +#define PRIVILEGED_FUNCTION +#define PRIVILEGED_DATA +#endif + +void _xt_coproc_release(volatile void *coproc_sa_base); + +/* + * The structures and methods of manipulating the MPU are contained within the + * port layer. + * + * Fills the xMPUSettings structure with the memory region information + * contained in xRegions. + */ +#if( portUSING_MPU_WRAPPERS == 1 ) +struct xMEMORY_REGION; +void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMORY_REGION *const xRegions, StackType_t *pxBottomOfStack, uint32_t usStackDepth ) PRIVILEGED_FUNCTION; +void vPortReleaseTaskMPUSettings( xMPU_SETTINGS *xMPUSettings ); +#endif + +// -------------------- Heap Related ----------------------- + +/** + * @brief Checks if a given piece of memory can be used to store a task's TCB + * + * - Defined in port_common.c + * + * @param ptr Pointer to memory + * @return true Memory can be used to store a TCB + * @return false Otherwise + */ +bool xPortCheckValidTCBMem(const void *ptr); + +/** + * @brief Checks if a given piece of memory can be used to store a task's stack + * + * - Defined in port_common.c + * + * @param ptr Pointer to memory + * @return true Memory can be used to store a task stack + * @return false Otherwise + */ +bool xPortcheckValidStackMem(const void *ptr); + +#define portVALID_TCB_MEM(ptr) xPortCheckValidTCBMem(ptr) +#define portVALID_STACK_MEM(ptr) xPortcheckValidStackMem(ptr) + +// --------------------- App-Trace ------------------------- + +#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 + +// --------------------- Debugging ------------------------- + +#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 + +/* ---------------------------------------------------- Deprecate ------------------------------------------------------ + * - Pull in header containing deprecated macros here + * ------------------------------------------------------------------------------------------------------------------ */ + +#include "portmacro_deprecated.h" + +#ifdef __cplusplus +} +#endif + +#endif // __ASSEMBLER__ + +#endif /* PORTMACRO_H */ diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/portmacro_deprecated.h b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/portmacro_deprecated.h new file mode 100644 index 0000000000..378617c73a --- /dev/null +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/portmacro_deprecated.h @@ -0,0 +1,93 @@ +/* + * SPDX-FileCopyrightText: 2017-2021 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* ---------------------------------------------------- Deprecate ------------------------------------------------------ + * - Macros or functions that should be deprecated in v5.0, then removed in the next major release + * - Kept as not to cause a breaking change + * - Include this header at the end of portmacro.h + * ------------------------------------------------------------------------------------------------------------------ */ + +/** + * @brief Disable interrupts in a nested manner + * + * Does the exact same thing as portSET_INTERRUPT_MASK_FROM_ISR() + * + * @deprecated This function is deprecated. Call portSET_INTERRUPT_MASK_FROM_ISR() instead + */ +static inline __attribute__((deprecated)) UBaseType_t portENTER_CRITICAL_NESTED(void) { + return portSET_INTERRUPT_MASK_FROM_ISR(); +} + +/** + * @brief Reenables interrupts in a nested manner + * + * Does the exact same thing as portCLEAR_INTERRUPT_MASK_FROM_ISR() + * + * @deprecated This function is deprecated. Call portCLEAR_INTERRUPT_MASK_FROM_ISR() instead + */ +static inline void __attribute__((deprecated)) portEXIT_CRITICAL_NESTED(UBaseType_t prev_level) +{ + portCLEAR_INTERRUPT_MASK_FROM_ISR(prev_level); +} + +/* ---------------------- Spinlocks --------------------- */ + +/** + * @brief Initialize a spinlock + * + * Does the exact same thing as spinlock_initialize(); + * + * @deprecated This function is deprecated. Call spinlock_initialize() instead + * @param[in] mux Spinlock + */ +static inline void __attribute__((deprecated)) __attribute__((always_inline)) vPortCPUInitializeMutex(portMUX_TYPE *mux) +{ + spinlock_initialize(mux); +} + +/** + * @brief Acquire a spinlock + * + * Does the exact same thing as spinlock_acquire() with unlimited timeout + * + * @deprecated This function is deprecated. Call spinlock_acquire() instead + * @param[in] mux Spinlock + */ +static inline void __attribute__((deprecated)) __attribute__((always_inline)) vPortCPUAcquireMutex(portMUX_TYPE *mux) +{ + spinlock_acquire(mux, portMUX_NO_TIMEOUT); +} + +/** + * @brief Acquire a spinlock + * + * Does the exact same thing as spinlock_acquire() with a specified timeout + * + * @deprecated This function is deprecated. Call spinlock_acquire() instead + * @note Does not have deprecated attribute due to usage in app_trace_util.c + * @param[in] mux Spinlock + * @param timeout + * @return true Spinlock acquired + * @return false Timed out + */ +static inline bool __attribute__((always_inline)) vPortCPUAcquireMutexTimeout(portMUX_TYPE *mux, int timeout) +{ + return (spinlock_acquire(mux, timeout)); +} + +/** + * @brief Release a spinlock + * + * Does the exact same thing as spinlock_release() + * + * @deprecated This function is deprecated. Call spinlock_release() instead + * @note Does not have deprecated attribute due to usage in app_trace_util.c + * @param[in] mux Spinlock + */ +static inline void __attribute__((always_inline)) vPortCPUReleaseMutex(portMUX_TYPE *mux) +{ + spinlock_release(mux); +} diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/xtensa_api.h b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/xtensa_api.h new file mode 100644 index 0000000000..bd2bfeb208 --- /dev/null +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/xtensa_api.h @@ -0,0 +1,2 @@ +/* This header file has been moved, please include in future */ +#include diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/xtensa_config.h b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/xtensa_config.h new file mode 100644 index 0000000000..f8b2557e31 --- /dev/null +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/xtensa_config.h @@ -0,0 +1,188 @@ +/* + * 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. + */ + +/* + * Configuration-specific information for Xtensa build. This file must be + * included in FreeRTOSConfig.h to properly set up the config-dependent + * parameters correctly. + * + * NOTE: To enable thread-safe C library support, XT_USE_THREAD_SAFE_CLIB must + * be defined to be > 0 somewhere above or on the command line. + */ + +#ifndef XTENSA_CONFIG_H +#define XTENSA_CONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include /* required for XSHAL_CLIB */ + +#include "xtensa_context.h" + + +/*----------------------------------------------------------------------------- +* STACK REQUIREMENTS +* +* This section defines the minimum stack size, and the extra space required to +* be allocated for saving coprocessor state and/or C library state information +* (if thread safety is enabled for the C library). The sizes are in bytes. +* +* Stack sizes for individual tasks should be derived from these minima based on +* the maximum call depth of the task and the maximum level of interrupt nesting. +* A minimum stack size is defined by XT_STACK_MIN_SIZE. This minimum is based +* on the requirement for a task that calls nothing else but can be interrupted. +* This assumes that interrupt handlers do not call more than a few levels deep. +* If this is not true, i.e. one or more interrupt handlers make deep calls then +* the minimum must be increased. +* +* If the Xtensa processor configuration includes coprocessors, then space is +* allocated to save the coprocessor state on the stack. +* +* If thread safety is enabled for the C runtime library, (XT_USE_THREAD_SAFE_CLIB +* is defined) then space is allocated to save the C library context in the TCB. +* +* Allocating insufficient stack space is a common source of hard-to-find errors. +* During development, it is best to enable the FreeRTOS stack checking features. +* +* Usage: +* +* XT_USE_THREAD_SAFE_CLIB -- Define this to a nonzero value to enable thread-safe +* use of the C library. This will require extra stack +* space to be allocated for tasks that use the C library +* reentrant functions. See below for more information. +* +* NOTE: The Xtensa toolchain supports multiple C libraries and not all of them +* support thread safety. Check your core configuration to see which C library +* was chosen for your system. +* +* XT_STACK_MIN_SIZE -- The minimum stack size for any task. It is recommended +* that you do not use a stack smaller than this for any +* task. In case you want to use stacks smaller than this +* size, you must verify that the smaller size(s) will work +* under all operating conditions. +* +* XT_STACK_EXTRA -- The amount of extra stack space to allocate for a task +* that does not make C library reentrant calls. Add this +* to the amount of stack space required by the task itself. +* +* XT_STACK_EXTRA_CLIB -- The amount of space to allocate for C library state. +* +-----------------------------------------------------------------------------*/ + +/* Extra space required for interrupt/exception hooks. */ +#ifdef XT_INTEXC_HOOKS + #ifdef __XTENSA_CALL0_ABI__ + #define STK_INTEXC_EXTRA 0x200 + #else + #define STK_INTEXC_EXTRA 0x180 + #endif +#else + #define STK_INTEXC_EXTRA 0 +#endif + +/* Check C library thread safety support and compute size of C library save area. + For the supported libraries, we enable thread safety by default, and this can + be overridden from the compiler/make command line. */ +#if (XSHAL_CLIB == XTHAL_CLIB_NEWLIB) || (XSHAL_CLIB == XTHAL_CLIB_XCLIB) + #ifndef XT_USE_THREAD_SAFE_CLIB + #define XT_USE_THREAD_SAFE_CLIB 1 + #endif +#else + #define XT_USE_THREAD_SAFE_CLIB 0 +#endif + +#if XT_USE_THREAD_SAFE_CLIB > 0u + #if XSHAL_CLIB == XTHAL_CLIB_XCLIB + #define XT_HAVE_THREAD_SAFE_CLIB 1 + #if !defined __ASSEMBLER__ + #include + #define XT_CLIB_CONTEXT_AREA_SIZE ((sizeof(struct _reent) + 15) + (-16)) + #define XT_CLIB_GLOBAL_PTR _reent_ptr + #define _REENT_INIT_PTR _init_reent + #define _impure_ptr _reent_ptr + + void _reclaim_reent(void * ptr); + #endif + #elif XSHAL_CLIB == XTHAL_CLIB_NEWLIB + #define XT_HAVE_THREAD_SAFE_CLIB 1 + #if !defined __ASSEMBLER__ + #include + #define XT_CLIB_CONTEXT_AREA_SIZE ((sizeof(struct _reent) + 15) + (-16)) + #define XT_CLIB_GLOBAL_PTR _impure_ptr + #endif + #else + #define XT_HAVE_THREAD_SAFE_CLIB 0 + #error The selected C runtime library is not thread safe. + #endif +#else + #define XT_CLIB_CONTEXT_AREA_SIZE 0 +#endif + +/*------------------------------------------------------------------------------ + Extra size -- interrupt frame plus coprocessor save area plus hook space. + NOTE: Make sure XT_INTEXC_HOOKS is undefined unless you really need the hooks. +------------------------------------------------------------------------------*/ +#ifdef __XTENSA_CALL0_ABI__ + #define XT_XTRA_SIZE (XT_STK_FRMSZ + STK_INTEXC_EXTRA + 0x10 + XT_CP_SIZE) +#else + #define XT_XTRA_SIZE (XT_STK_FRMSZ + STK_INTEXC_EXTRA + 0x20 + XT_CP_SIZE) +#endif + +/*------------------------------------------------------------------------------ + Space allocated for user code -- function calls and local variables. + NOTE: This number can be adjusted to suit your needs. You must verify that the + amount of space you reserve is adequate for the worst-case conditions in your + application. + NOTE: The windowed ABI requires more stack, since space has to be reserved + for spilling register windows. +------------------------------------------------------------------------------*/ +#ifdef __XTENSA_CALL0_ABI__ + #define XT_USER_SIZE 0x200 +#else + #define XT_USER_SIZE 0x400 +#endif + +/* Minimum recommended stack size. */ +#define XT_STACK_MIN_SIZE ((XT_XTRA_SIZE + XT_USER_SIZE) / sizeof(unsigned char)) + +/* OS overhead with and without C library thread context. */ +#define XT_STACK_EXTRA (XT_XTRA_SIZE) +#define XT_STACK_EXTRA_CLIB (XT_XTRA_SIZE + XT_CLIB_CONTEXT_AREA_SIZE) + + +#ifdef __cplusplus +} +#endif + +#endif /* XTENSA_CONFIG_H */ diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/xtensa_context.h b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/xtensa_context.h new file mode 100644 index 0000000000..45c4272869 --- /dev/null +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/xtensa_context.h @@ -0,0 +1,2 @@ +/* This header file has been moved, please include in future */ +#include diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/xtensa_rtos.h b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/xtensa_rtos.h new file mode 100644 index 0000000000..f2e2f99ccc --- /dev/null +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/xtensa_rtos.h @@ -0,0 +1,241 @@ +/* + * 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. + */ + +/* + * RTOS-SPECIFIC INFORMATION FOR XTENSA RTOS ASSEMBLER SOURCES + * (FreeRTOS Port) + * + * This header is the primary glue between generic Xtensa RTOS support + * sources and a specific RTOS port for Xtensa. It contains definitions + * and macros for use primarily by Xtensa assembly coded source files. + * + * Macros in this header map callouts from generic Xtensa files to specific + * RTOS functions. It may also be included in C source files. + * + * Xtensa RTOS ports support all RTOS-compatible configurations of the Xtensa + * architecture, using the Xtensa hardware abstraction layer (HAL) to deal + * with configuration specifics. + * + * Should be included by all Xtensa generic and RTOS port-specific sources. + */ + +#ifndef XTENSA_RTOS_H +#define XTENSA_RTOS_H + +#ifdef __ASSEMBLER__ +#include +#else +#include +#endif + +#include +#include +#include "sdkconfig.h" + +/* +Include any RTOS specific definitions that are needed by this header. +*/ +#include "freertos/FreeRTOSConfig.h" + +/* +Convert FreeRTOSConfig definitions to XTENSA definitions. +However these can still be overridden from the command line. +*/ + +#ifndef XT_SIMULATOR + #if configXT_SIMULATOR + #define XT_SIMULATOR 1 /* Simulator mode */ + #endif +#endif + +#ifndef XT_BOARD + #if configXT_BOARD + #define XT_BOARD 1 /* Board mode */ + #endif +#endif + +#ifndef XT_TIMER_INDEX + #if defined configXT_TIMER_INDEX + #define XT_TIMER_INDEX configXT_TIMER_INDEX /* Index of hardware timer to be used */ + #endif +#endif + +#ifndef XT_INTEXC_HOOKS + #if configXT_INTEXC_HOOKS + #define XT_INTEXC_HOOKS 1 /* Enables exception hooks */ + #endif +#endif + +#if (!XT_SIMULATOR) && (!XT_BOARD) + #error Either XT_SIMULATOR or XT_BOARD must be defined. +#endif + + +/* +Name of RTOS (for messages). +*/ +#define XT_RTOS_NAME FreeRTOS + +/* +Check some Xtensa configuration requirements and report error if not met. +Error messages can be customize to the RTOS port. +*/ + +#if !XCHAL_HAVE_XEA2 +#error "FreeRTOS/Xtensa requires XEA2 (exception architecture 2)." +#endif + + +/******************************************************************************* + +RTOS CALLOUT MACROS MAPPED TO RTOS PORT-SPECIFIC FUNCTIONS. + +Define callout macros used in generic Xtensa code to interact with the RTOS. +The macros are simply the function names for use in calls from assembler code. +Some of these functions may call back to generic functions in xtensa_context.h . + +*******************************************************************************/ + +/* +Inform RTOS of entry into an interrupt handler that will affect it. +Allows RTOS to manage switch to any system stack and count nesting level. +Called after minimal context has been saved, with interrupts disabled. +RTOS port can call0 _xt_context_save to save the rest of the context. +May only be called from assembly code by the 'call0' instruction. +*/ +// void XT_RTOS_INT_ENTER(void) +#define XT_RTOS_INT_ENTER _frxt_int_enter + +/* +Inform RTOS of completion of an interrupt handler, and give control to +RTOS to perform thread/task scheduling, switch back from any system stack +and restore the context, and return to the exit dispatcher saved in the +stack frame at XT_STK_EXIT. RTOS port can call0 _xt_context_restore +to save the context saved in XT_RTOS_INT_ENTER via _xt_context_save, +leaving only a minimal part of the context to be restored by the exit +dispatcher. This function does not return to the place it was called from. +May only be called from assembly code by the 'call0' instruction. +*/ +// void XT_RTOS_INT_EXIT(void) +#define XT_RTOS_INT_EXIT _frxt_int_exit + +/* +Inform RTOS of the occurrence of a tick timer interrupt. +If RTOS has no tick timer, leave XT_RTOS_TIMER_INT undefined. +May be coded in or called from C or assembly, per ABI conventions. +RTOS may optionally define XT_TICK_PER_SEC in its own way (eg. macro). +*/ +// void XT_RTOS_TIMER_INT(void) +#ifdef CONFIG_FREERTOS_SYSTICK_USES_CCOUNT +#define XT_RTOS_TIMER_INT _frxt_timer_int +#endif +#define XT_TICK_PER_SEC configTICK_RATE_HZ + +/* +Return in a15 the base address of the co-processor state save area for the +thread that triggered a co-processor exception, or 0 if no thread was running. +The state save area is structured as defined in xtensa_context.h and has size +XT_CP_SIZE. Co-processor instructions should only be used in thread code, never +in interrupt handlers or the RTOS kernel. May only be called from assembly code +and by the 'call0' instruction. A result of 0 indicates an unrecoverable error. +The implementation may use only a2-4, a15 (all other regs must be preserved). +*/ +// void* XT_RTOS_CP_STATE(void) +#define XT_RTOS_CP_STATE _frxt_task_coproc_state + + +/******************************************************************************* + +HOOKS TO DYNAMICALLY INSTALL INTERRUPT AND EXCEPTION HANDLERS PER LEVEL. + +This Xtensa RTOS port provides hooks for dynamically installing exception +and interrupt handlers to facilitate automated testing where each test +case can install its own handler for user exceptions and each interrupt +priority (level). This consists of an array of function pointers indexed +by interrupt priority, with index 0 being the user exception handler hook. +Each entry in the array is initially 0, and may be replaced by a function +pointer of type XT_INTEXC_HOOK. A handler may be uninstalled by installing 0. + +The handler for low and medium priority obeys ABI conventions so may be coded +in C. For the exception handler, the cause is the contents of the EXCCAUSE +reg, and the result is -1 if handled, else the cause (still needs handling). +For interrupt handlers, the cause is a mask of pending enabled interrupts at +that level, and the result is the same mask with the bits for the handled +interrupts cleared (those not cleared still need handling). This allows a test +case to either pre-handle or override the default handling for the exception +or interrupt level (see xtensa_vectors.S). + +High priority handlers (including NMI) must be coded in assembly, are always +called by 'call0' regardless of ABI, must preserve all registers except a0, +and must not use or modify the interrupted stack. The hook argument 'cause' +is not passed and the result is ignored, so as not to burden the caller with +saving and restoring a2 (it assumes only one interrupt per level - see the +discussion in high priority interrupts in xtensa_vectors.S). The handler +therefore should be coded to prototype 'void h(void)' even though it plugs +into an array of handlers of prototype 'unsigned h(unsigned)'. + +To enable interrupt/exception hooks, compile the RTOS with '-DXT_INTEXC_HOOKS'. + +*******************************************************************************/ + +#define XT_INTEXC_HOOK_NUM (1 + XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI) + +#ifndef __ASSEMBLER__ +typedef unsigned (*XT_INTEXC_HOOK)(unsigned cause); +extern volatile XT_INTEXC_HOOK _xt_intexc_hooks[XT_INTEXC_HOOK_NUM]; +#endif + + +/******************************************************************************* + +CONVENIENCE INCLUSIONS. + +Ensures RTOS specific files need only include this one Xtensa-generic header. +These headers are included last so they can use the RTOS definitions above. + +*******************************************************************************/ + +#include "xtensa_context.h" + +#ifdef XT_RTOS_TIMER_INT +#include "xtensa_timer.h" +#endif + + +/******************************************************************************* + +Xtensa Port Version. + +*******************************************************************************/ + +#define XTENSA_PORT_VERSION 1.7 +#define XTENSA_PORT_VERSION_STRING "1.7" + +#endif /* XTENSA_RTOS_H */ diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/xtensa_timer.h b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/xtensa_timer.h new file mode 100644 index 0000000000..53555ed8cd --- /dev/null +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos/xtensa_timer.h @@ -0,0 +1,165 @@ +/* + * 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 INFORMATION FOR RTOS TICK TIMER AND CLOCK FREQUENCY + * + * 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. + * + * Edit this file to modify timer selection and to specify clock frequency and + * tick duration to match timer interrupt to the real-time tick duration. + * + * If the RTOS has no timer interrupt, then there is no tick timer and the + * clock frequency is irrelevant, so all of these macros are left undefined + * and the Xtensa core configuration need not have a timer. + */ + +#ifndef XTENSA_TIMER_H +#define XTENSA_TIMER_H + +#ifdef __ASSEMBLER__ +#include +#endif + +#include +#include + +#include "xtensa_rtos.h" /* in case this wasn't included directly */ + +#include "freertos/FreeRTOSConfig.h" + +/* +Select timer to use for periodic tick, and determine its interrupt number +and priority. User may specify a timer by defining XT_TIMER_INDEX with -D, +in which case its validity is checked (it must exist in this core and must +not be on a high priority interrupt - an error will be reported in invalid). +Otherwise select the first low or medium priority interrupt timer available. +*/ +#if XCHAL_NUM_TIMERS == 0 + + #error "This Xtensa configuration is unsupported, it has no timers." + +#else + +#ifndef XT_TIMER_INDEX + #if XCHAL_TIMER3_INTERRUPT != XTHAL_TIMER_UNCONFIGURED + #if XCHAL_INT_LEVEL(XCHAL_TIMER3_INTERRUPT) <= XCHAL_EXCM_LEVEL + #undef XT_TIMER_INDEX + #define XT_TIMER_INDEX 3 + #endif + #endif + #if XCHAL_TIMER2_INTERRUPT != XTHAL_TIMER_UNCONFIGURED + #if XCHAL_INT_LEVEL(XCHAL_TIMER2_INTERRUPT) <= XCHAL_EXCM_LEVEL + #undef XT_TIMER_INDEX + #define XT_TIMER_INDEX 2 + #endif + #endif + #if XCHAL_TIMER1_INTERRUPT != XTHAL_TIMER_UNCONFIGURED + #if XCHAL_INT_LEVEL(XCHAL_TIMER1_INTERRUPT) <= XCHAL_EXCM_LEVEL + #undef XT_TIMER_INDEX + #define XT_TIMER_INDEX 1 + #endif + #endif + #if XCHAL_TIMER0_INTERRUPT != XTHAL_TIMER_UNCONFIGURED + #if XCHAL_INT_LEVEL(XCHAL_TIMER0_INTERRUPT) <= XCHAL_EXCM_LEVEL + #undef XT_TIMER_INDEX + #define XT_TIMER_INDEX 0 + #endif + #endif +#endif +#ifndef XT_TIMER_INDEX + #error "There is no suitable timer in this Xtensa configuration." +#endif + +#define XT_CCOMPARE (CCOMPARE + XT_TIMER_INDEX) +#define XT_TIMER_INTNUM XCHAL_TIMER_INTERRUPT(XT_TIMER_INDEX) +#define XT_TIMER_INTPRI XCHAL_INT_LEVEL(XT_TIMER_INTNUM) +#define XT_TIMER_INTEN (1 << XT_TIMER_INTNUM) + +#if XT_TIMER_INTNUM == XTHAL_TIMER_UNCONFIGURED + #error "The timer selected by XT_TIMER_INDEX does not exist in this core." +#elif XT_TIMER_INTPRI > XCHAL_EXCM_LEVEL + #error "The timer interrupt cannot be high priority (use medium or low)." +#endif + +#endif /* XCHAL_NUM_TIMERS */ + +/* +Set processor clock frequency, used to determine clock divisor for timer tick. +User should BE SURE TO ADJUST THIS for the Xtensa platform being used. +If using a supported board via the board-independent API defined in xtbsp.h, +this may be left undefined and frequency and tick divisor will be computed +and cached during run-time initialization. + +NOTE ON SIMULATOR: +Under the Xtensa instruction set simulator, the frequency can only be estimated +because it depends on the speed of the host and the version of the simulator. +Also because it runs much slower than hardware, it is not possible to achieve +real-time performance for most applications under the simulator. A frequency +too low does not allow enough time between timer interrupts, starving threads. +To obtain a more convenient but non-real-time tick duration on the simulator, +compile with xt-xcc option "-DXT_SIMULATOR". +Adjust this frequency to taste (it's not real-time anyway!). +*/ +#if defined(XT_SIMULATOR) && !defined(XT_CLOCK_FREQ) +#define XT_CLOCK_FREQ configCPU_CLOCK_HZ +#endif + +#if !defined(XT_CLOCK_FREQ) && !defined(XT_BOARD) + #error "XT_CLOCK_FREQ must be defined for the target platform." +#endif + +/* +Default number of timer "ticks" per second (default 100 for 10ms tick). +RTOS may define this in its own way (if applicable) in xtensa_rtos.h. +User may redefine this to an optimal value for the application, either by +editing this here or in xtensa_rtos.h, or compiling with xt-xcc option +"-DXT_TICK_PER_SEC=" where is a suitable number. +*/ +#ifndef XT_TICK_PER_SEC +#define XT_TICK_PER_SEC configTICK_RATE_HZ /* 10 ms tick = 100 ticks per second */ +#endif + +/* +Derivation of clock divisor for timer tick and interrupt (one per tick). +*/ +#ifdef XT_CLOCK_FREQ +#define XT_TICK_DIVISOR (XT_CLOCK_FREQ / XT_TICK_PER_SEC) +#endif + +#ifndef __ASSEMBLER__ +extern unsigned _xt_tick_divisor; +extern void _xt_tick_divisor_init(void); +#endif + +#endif /* XTENSA_TIMER_H */ diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c new file mode 100644 index 0000000000..15729559ff --- /dev/null +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c @@ -0,0 +1,484 @@ +/* + * SPDX-FileCopyrightText: 2017 Amazon.com, Inc. or its affiliates + * SPDX-FileCopyrightText: 2015-2019 Cadence Design Systems, Inc. + * + * 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! + */ + +/* + * 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 "sdkconfig.h" +#include +#include +#include +#include +#include +#include "soc/soc_caps.h" +#include "esp_private/crosscore_int.h" +#include "esp_system.h" +#include "esp_log.h" +#include "esp_int_wdt.h" +#ifdef CONFIG_APPTRACE_ENABLE +#include "esp_app_trace.h" /* Required for esp_apptrace_init. [refactor-todo] */ +#endif +#include "FreeRTOS.h" /* This pulls in portmacro.h */ +#include "task.h" /* Required for TaskHandle_t, tskNO_AFFINITY, and vTaskStartScheduler */ +#include "port_systick.h" +#include "esp_cpu.h" + +_Static_assert(tskNO_AFFINITY == CONFIG_FREERTOS_NO_AFFINITY, "incorrect tskNO_AFFINITY value"); + + +/* ---------------------------------------------------- Variables ------------------------------------------------------ + * + * ------------------------------------------------------------------------------------------------------------------ */ + +static const char *TAG = "cpu_start"; /* [refactor-todo]: might be appropriate to change in the future, but for now maintain the same log output */ +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 +BaseType_t port_uxCriticalNesting[portNUM_PROCESSORS] = {0}; +BaseType_t port_uxOldInterruptState[portNUM_PROCESSORS] = {0}; + + +/* ------------------------------------------------ FreeRTOS Portable -------------------------------------------------- + * - Provides implementation for functions required by FreeRTOS + * - Declared in portable.h + * ------------------------------------------------------------------------------------------------------------------ */ + +// ----------------- Scheduler Start/End ------------------- + +/* Defined in xtensa_context.S */ +extern void _xt_coproc_init(void); + +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 + /* Initialize co-processor management for tasks. Leave CPENABLE alone. */ + _xt_coproc_init(); +#endif + + /* Setup the hardware to generate the tick. */ + vPortSetupTimer(); + + port_xSchedulerRunning[xPortGetCoreID()] = 1; + + // Cannot be directly called from C; never returns + __asm__ volatile ("call0 _frxt_dispatch\n"); + + /* Should not get here. */ + return pdTRUE; +} + +void vPortEndScheduler( void ) +{ + /* It is unlikely that the Xtensa port will get stopped. If required simply + disable the tick interrupt here. */ + abort(); +} + +// ------------------------ Stack -------------------------- + +// 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 = pcTaskGetName(NULL); + ESP_LOGE("FreeRTOS", "FreeRTOS Task \"%s\" should not return, Aborting now!", pcTaskName); + abort(); +} +#endif + +#if portUSING_MPU_WRAPPERS +StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters, BaseType_t xRunPrivileged ) +#else +StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters ) +#endif +{ + StackType_t *sp, *tp; + XtExcFrame *frame; +#if XCHAL_CP_NUM > 0 + uint32_t *p; +#endif + 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. */ + 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) { + *tp = 0; + } + + 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 */ + + /* 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 /* __XTENSA_CALL0_ABI__ */ + /* + 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; +#endif + frame->ps = PS_UM | PS_EXCM | PS_WOE | PS_CALLINC(1); +#endif /* __XTENSA_CALL0_ABI__ */ + +#ifdef XT_USE_SWPRI + /* Set the initial virtual priority mask value to all 1's. */ + frame->vpri = 0xFFFFFFFF; +#endif + + /* Init threadptr register and set up TLS run-time area. + * The diagram in port/riscv/port.c illustrates the calculations below. + */ + 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. + * Note this is slightly different compared to the RISC-V port, where offset = address - tls_section_vma. + */ + 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) */ + /* No access to TCB here, so derive indirectly. Stack growth is top to bottom. + * //p = (uint32_t *) xMPUSettings->coproc_area; + */ + p = (uint32_t *)(((uint32_t) pxTopOfStack - XT_CP_SIZE) & ~0xf); + configASSERT( ( uint32_t ) p >= frame->a1 ); + p[0] = 0; + p[1] = 0; + p[2] = (((uint32_t) p) + 12 + XCHAL_TOTAL_SA_ALIGN - 1) & -XCHAL_TOTAL_SA_ALIGN; +#endif /* XCHAL_CP_NUM */ + + return sp; +} + + + +/* ---------------------------------------------- Port Implementations ------------------------------------------------- + * + * ------------------------------------------------------------------------------------------------------------------ */ + +// --------------------- Interrupts ------------------------ + +BaseType_t xPortInIsrContext(void) +{ + unsigned int irqStatus; + BaseType_t ret; + irqStatus = portSET_INTERRUPT_MASK_FROM_ISR(); + ret = (port_interruptNesting[xPortGetCoreID()] != 0); + portCLEAR_INTERRUPT_MASK_FROM_ISR(irqStatus); + return ret; +} + +void vPortAssertIfInISR(void) +{ + configASSERT(xPortInIsrContext()); +} + +BaseType_t IRAM_ATTR xPortInterruptedFromISRContext(void) +{ + return (port_interruptNesting[xPortGetCoreID()] != 0); +} + +// ------------------ Critical Sections -------------------- + +BaseType_t __attribute__((optimize("-O3"))) xPortEnterCriticalTimeout(portMUX_TYPE *mux, BaseType_t timeout) +{ + /* Interrupts may already be disabled (if this function is called in nested + * manner). However, there's no atomic operation that will allow us to check, + * thus we have to disable interrupts again anyways. + * + * However, if this is call is NOT nested (i.e., the first call to enter a + * critical section), we will save the previous interrupt level so that the + * saved level can be restored on the last call to exit the critical. + */ + BaseType_t xOldInterruptLevel = portSET_INTERRUPT_MASK_FROM_ISR(); + if (!spinlock_acquire(mux, timeout)) { + //Timed out attempting to get spinlock. Restore previous interrupt level and return + portCLEAR_INTERRUPT_MASK_FROM_ISR(xOldInterruptLevel); + return pdFAIL; + } + //Spinlock acquired. Increment the critical nesting count. + BaseType_t coreID = xPortGetCoreID(); + BaseType_t newNesting = port_uxCriticalNesting[coreID] + 1; + port_uxCriticalNesting[coreID] = newNesting; + //If this is the first entry to a critical section. Save the old interrupt level. + if ( newNesting == 1 ) { + port_uxOldInterruptState[coreID] = xOldInterruptLevel; + } + return pdPASS; +} + +void __attribute__((optimize("-O3"))) vPortExitCritical(portMUX_TYPE *mux) +{ + /* This function may be called in a nested manner. Therefore, we only need + * to reenable interrupts if this is the last call to exit the critical. We + * can use the nesting count to determine whether this is the last exit call. + */ + spinlock_release(mux); + BaseType_t coreID = xPortGetCoreID(); + BaseType_t nesting = port_uxCriticalNesting[coreID]; + + if (nesting > 0) { + nesting--; + port_uxCriticalNesting[coreID] = nesting; + //This is the last exit call, restore the saved interrupt level + if ( nesting == 0 ) { + portCLEAR_INTERRUPT_MASK_FROM_ISR(port_uxOldInterruptState[coreID]); + } + } +} + +BaseType_t xPortEnterCriticalTimeoutCompliance(portMUX_TYPE *mux, BaseType_t timeout) +{ + BaseType_t ret; + if (!xPortInIsrContext()) { + ret = xPortEnterCriticalTimeout(mux, timeout); + } else { + esp_rom_printf("port*_CRITICAL called from ISR context. Aborting!\n"); + abort(); + ret = pdFAIL; + } + return ret; +} + +void vPortExitCriticalCompliance(portMUX_TYPE *mux) +{ + if (!xPortInIsrContext()) { + vPortExitCritical(mux); + } else { + esp_rom_printf("port*_CRITICAL called from ISR context. Aborting!\n"); + abort(); + } +} + +// ---------------------- Yielding ------------------------- + +void vPortYieldOtherCore( BaseType_t coreid ) +{ + esp_crosscore_int_send_yield( coreid ); +} + +// ------------------- Hook Functions ---------------------- + +void __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName ) +{ +#define ERR_STR1 "***ERROR*** A stack overflow in task " +#define ERR_STR2 " has been detected." + const char *str[] = {ERR_STR1, pcTaskName, ERR_STR2}; + + char buf[sizeof(ERR_STR1) + CONFIG_FREERTOS_MAX_TASK_NAME_LEN + sizeof(ERR_STR2) + 1 /* null char */] = { 0 }; + + char *dest = buf; + for (size_t i = 0 ; i < sizeof(str) / sizeof(str[0]); i++) { + dest = strcat(dest, str[i]); + } + esp_system_abort(buf); +} + +// ----------------------- System -------------------------- + +uint32_t xPortGetTickRateHz(void) +{ + return (uint32_t)configTICK_RATE_HZ; +} + + +#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. + //Unfortunately, the Xtensa watchpoints can't set a watchpoint on a random [base - base+n] region because + //the size works by masking off the lowest address bits. For that reason, we futz a bit and watch the lowest 32 + //bytes of the stack we can actually watch. In general, this can cause the watchpoint to be triggered at most + //28 bytes early. The value 32 is chosen because it's larger than the stack canary, which in FreeRTOS is 20 bytes. + //This way, we make sure we trigger before/when the stack canary is corrupted, not after. + int addr = (int)pxStackStart; + addr = (addr + 31) & (~31); + esp_cpu_set_watchpoint(STACK_WATCH_POINT_NUMBER, (char *)addr, 32, ESP_CPU_WATCHPOINT_STORE); +} + +/* ---------------------------------------------- Misc Implementations ------------------------------------------------- + * + * ------------------------------------------------------------------------------------------------------------------ */ + +// -------------------- Co-Processor ----------------------- + +/* + * Used to set coprocessor area in stack. Current hack is to reuse MPU pointer for coprocessor area. + */ +#if portUSING_MPU_WRAPPERS +void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMORY_REGION *const xRegions, StackType_t *pxBottomOfStack, uint32_t usStackDepth ) +{ +#if XCHAL_CP_NUM > 0 + xMPUSettings->coproc_area = ( StackType_t * ) ( ( uint32_t ) ( pxBottomOfStack + usStackDepth - 1 )); + 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(). + */ +#endif +} + +void vPortReleaseTaskMPUSettings( xMPU_SETTINGS *xMPUSettings ) +{ + /* If task has live floating point registers somewhere, release them */ + _xt_coproc_release( xMPUSettings->coproc_area ); +} +#endif /* portUSING_MPU_WRAPPERS */ + +// --------------------- App Start-up ---------------------- + +#if !CONFIG_FREERTOS_UNICORE +void esp_startup_start_app_other_cores(void) +{ + // For now, we only support up to two core: 0 and 1. + if (xPortGetCoreID() >= 2) { + abort(); + } + + // Wait for FreeRTOS initialization to finish on PRO CPU + while (port_xSchedulerRunning[0] == 0) { + ; + } + +#if CONFIG_APPTRACE_ENABLE + // [refactor-todo] move to esp_system initialization + esp_err_t err = esp_apptrace_init(); + assert(err == ESP_OK && "Failed to init apptrace module on APP CPU!"); +#endif + +#if CONFIG_ESP_INT_WDT + //Initialize the interrupt watch dog for CPU1. + esp_int_wdt_cpu_init(); +#endif + + esp_crosscore_int_init(); + + ESP_EARLY_LOGI(TAG, "Starting scheduler on APP CPU."); + xPortStartScheduler(); + abort(); /* Only get to here if FreeRTOS somehow very broken */ +} +#endif // !CONFIG_FREERTOS_UNICORE + +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(TAG, "Starting scheduler on PRO CPU."); + vTaskStartScheduler(); +} diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/portasm.S b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/portasm.S new file mode 100644 index 0000000000..27b76d97b4 --- /dev/null +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/portasm.S @@ -0,0 +1,679 @@ +/* + * 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. + */ + +#include "xtensa_rtos.h" +#include "sdkconfig.h" + +#define TOPOFSTACK_OFFS 0x00 /* StackType_t *pxTopOfStack */ +#define CP_TOPOFSTACK_OFFS 0x04 /* xMPU_SETTINGS.coproc_area */ + +.extern pxCurrentTCB + +/* +******************************************************************************* +* Interrupt stack. The size of the interrupt stack is determined by the config +* parameter "configISR_STACK_SIZE" in FreeRTOSConfig.h +******************************************************************************* +*/ + .data + .align 16 + .global port_IntStack + .global port_switch_flag //Required by sysview_tracing build +port_IntStack: + .space configISR_STACK_SIZE*portNUM_PROCESSORS /* This allocates stacks for each individual CPU. */ +port_IntStackTop: + .word 0 +port_switch_flag: + .space portNUM_PROCESSORS*4 /* One flag for each individual CPU. */ + + .text + +/* +******************************************************************************* +* _frxt_setup_switch +* void _frxt_setup_switch(void); +* +* Sets an internal flag indicating that a task switch is required on return +* from interrupt handling. +* +******************************************************************************* +*/ + .global _frxt_setup_switch + .type _frxt_setup_switch,@function + .align 4 +_frxt_setup_switch: + + ENTRY(16) + + getcoreid a3 + movi a2, port_switch_flag + addx4 a2, a3, a2 + movi a3, 1 + s32i a3, a2, 0 + + RET(16) + +/* +******************************************************************************* +* _frxt_int_enter +* void _frxt_int_enter(void) +* +* Implements the Xtensa RTOS porting layer's XT_RTOS_INT_ENTER function for +* freeRTOS. Saves the rest of the interrupt context (not already saved). +* May only be called from assembly code by the 'call0' instruction, with +* interrupts disabled. +* See the detailed description of the XT_RTOS_ENTER macro in xtensa_rtos.h. +* +******************************************************************************* +*/ + .globl _frxt_int_enter + .type _frxt_int_enter,@function + .align 4 +_frxt_int_enter: + + /* Save a12-13 in the stack frame as required by _xt_context_save. */ + s32i a12, a1, XT_STK_A12 + s32i a13, a1, XT_STK_A13 + + /* Save return address in a safe place (free a0). */ + mov a12, a0 + + /* Save the rest of the interrupted context (preserves A12-13). */ + call0 _xt_context_save + + /* + Save interrupted task's SP in TCB only if not nesting. + Manage nesting directly rather than call the generic IntEnter() + (in windowed ABI we can't call a C function here anyway because PS.EXCM is still set). + */ + getcoreid a4 + movi a2, port_xSchedulerRunning + addx4 a2, a4, a2 + movi a3, port_interruptNesting + addx4 a3, a4, a3 + l32i a2, a2, 0 /* a2 = port_xSchedulerRunning */ + beqz a2, 1f /* scheduler not running, no tasks */ + l32i a2, a3, 0 /* a2 = port_interruptNesting */ + addi a2, a2, 1 /* increment nesting count */ + s32i a2, a3, 0 /* save nesting count */ + bnei a2, 1, .Lnested /* !=0 before incr, so nested */ + + movi a2, pxCurrentTCB + addx4 a2, a4, a2 + l32i a2, a2, 0 /* a2 = current TCB */ + beqz a2, 1f + s32i a1, a2, TOPOFSTACK_OFFS /* pxCurrentTCB->pxTopOfStack = SP */ + movi a1, port_IntStack+configISR_STACK_SIZE /* a1 = top of intr stack for CPU 0 */ + movi a2, configISR_STACK_SIZE /* add configISR_STACK_SIZE * cpu_num to arrive at top of stack for cpu_num */ + mull a2, a4, a2 + add a1, a1, a2 /* for current proc */ + + #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 + +.Lnested: +1: + #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 + + mov a0, a12 /* restore return addr and return */ + ret + +/* +******************************************************************************* +* _frxt_int_exit +* void _frxt_int_exit(void) +* +* Implements the Xtensa RTOS porting layer's XT_RTOS_INT_EXIT function for +* FreeRTOS. If required, calls vPortYieldFromInt() to perform task context +* switching, restore the (possibly) new task's context, and return to the +* exit dispatcher saved in the task's stack frame at XT_STK_EXIT. +* May only be called from assembly code by the 'call0' instruction. Does not +* return to caller. +* See the description of the XT_RTOS_ENTER macro in xtensa_rtos.h. +* +******************************************************************************* +*/ + .globl _frxt_int_exit + .type _frxt_int_exit,@function + .align 4 +_frxt_int_exit: + + getcoreid a4 + movi a2, port_xSchedulerRunning + addx4 a2, a4, a2 + movi a3, port_interruptNesting + addx4 a3, a4, a3 + rsil a0, XCHAL_EXCM_LEVEL /* lock out interrupts */ + l32i a2, a2, 0 /* a2 = port_xSchedulerRunning */ + beqz a2, .Lnoswitch /* scheduler not running, no tasks */ + l32i a2, a3, 0 /* a2 = port_interruptNesting */ + addi a2, a2, -1 /* decrement nesting count */ + s32i a2, a3, 0 /* save nesting count */ + bnez a2, .Lnesting /* !=0 after decr so still nested */ + + #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 + + movi a2, pxCurrentTCB + addx4 a2, a4, a2 + l32i a2, a2, 0 /* a2 = current TCB */ + beqz a2, 1f /* no task ? go to dispatcher */ + l32i a1, a2, TOPOFSTACK_OFFS /* SP = pxCurrentTCB->pxTopOfStack */ + + movi a2, port_switch_flag /* address of switch flag */ + addx4 a2, a4, a2 /* point to flag for this cpu */ + l32i a3, a2, 0 /* a3 = port_switch_flag */ + beqz a3, .Lnoswitch /* flag = 0 means no switch reqd */ + movi a3, 0 + s32i a3, a2, 0 /* zero out the flag for next time */ + +1: + /* + Call0 ABI callee-saved regs a12-15 need to be saved before possible preemption. + However a12-13 were already saved by _frxt_int_enter(). + */ + #ifdef __XTENSA_CALL0_ABI__ + s32i a14, a1, XT_STK_A14 + s32i a15, a1, XT_STK_A15 + #endif + + #ifdef __XTENSA_CALL0_ABI__ + call0 vPortYieldFromInt /* call dispatch inside the function; never returns */ + #else + call4 vPortYieldFromInt /* this one returns */ + call0 _frxt_dispatch /* tail-call dispatcher */ + /* Never returns here. */ + #endif + +.Lnoswitch: + /* + If we came here then about to resume the interrupted task. + */ + +.Lnesting: + /* + We come here only if there was no context switch, that is if this + is a nested interrupt, or the interrupted task was not preempted. + In either case there's no need to load the SP. + */ + + /* Restore full context from interrupt stack frame */ + call0 _xt_context_restore + + /* + Must return via the exit dispatcher corresponding to the entrypoint from which + this was called. Interruptee's A0, A1, PS, PC are restored and the interrupt + stack frame is deallocated in the exit dispatcher. + */ + l32i a0, a1, XT_STK_EXIT + ret + + +/* +********************************************************************************************************** +* _frxt_timer_int +* void _frxt_timer_int(void) +* +* Implements the Xtensa RTOS porting layer's XT_RTOS_TIMER_INT function for FreeRTOS. +* Called every timer interrupt. +* Manages the tick timer and calls xPortSysTickHandler() every tick. +* See the detailed description of the XT_RTOS_ENTER macro in xtensa_rtos.h. +* +* Callable from C (obeys ABI conventions). Implemented in assmebly code for performance. +* +********************************************************************************************************** +*/ +#ifdef CONFIG_FREERTOS_SYSTICK_USES_CCOUNT + .globl _frxt_timer_int + .type _frxt_timer_int,@function + .align 4 +_frxt_timer_int: + + /* + Xtensa timers work by comparing a cycle counter with a preset value. Once the match occurs + an interrupt is generated, and the handler has to set a new cycle count into the comparator. + To avoid clock drift due to interrupt latency, the new cycle count is computed from the old, + not the time the interrupt was serviced. However if a timer interrupt is ever serviced more + than one tick late, it is necessary to process multiple ticks until the new cycle count is + in the future, otherwise the next timer interrupt would not occur until after the cycle + counter had wrapped (2^32 cycles later). + + do { + ticks++; + old_ccompare = read_ccompare_i(); + write_ccompare_i( old_ccompare + divisor ); + service one tick; + diff = read_ccount() - old_ccompare; + } while ( diff > divisor ); + */ + + ENTRY(16) + + #ifdef CONFIG_PM_TRACE + movi a6, 1 /* = ESP_PM_TRACE_TICK */ + getcoreid a7 + call4 esp_pm_trace_enter + #endif // CONFIG_PM_TRACE + +.L_xt_timer_int_catchup: + + /* Update the timer comparator for the next tick. */ + #ifdef XT_CLOCK_FREQ + movi a2, XT_TICK_DIVISOR /* a2 = comparator increment */ + #else + movi a3, _xt_tick_divisor + l32i a2, a3, 0 /* a2 = comparator increment */ + #endif + rsr a3, XT_CCOMPARE /* a3 = old comparator value */ + add a4, a3, a2 /* a4 = new comparator value */ + wsr a4, XT_CCOMPARE /* update comp. and clear interrupt */ + esync + + #ifdef __XTENSA_CALL0_ABI__ + /* Preserve a2 and a3 across C calls. */ + s32i a2, sp, 4 + s32i a3, sp, 8 + #endif + + /* Call the FreeRTOS tick handler (see port_systick.c). */ + #ifdef __XTENSA_CALL0_ABI__ + call0 xPortSysTickHandler + #else + call4 xPortSysTickHandler + #endif + + #ifdef __XTENSA_CALL0_ABI__ + /* Restore a2 and a3. */ + l32i a2, sp, 4 + l32i a3, sp, 8 + #endif + + /* Check if we need to process more ticks to catch up. */ + esync /* ensure comparator update complete */ + rsr a4, CCOUNT /* a4 = cycle count */ + sub a4, a4, a3 /* diff = ccount - old comparator */ + blt a2, a4, .L_xt_timer_int_catchup /* repeat while diff > divisor */ + +#ifdef CONFIG_PM_TRACE + movi a6, 1 /* = ESP_PM_TRACE_TICK */ + getcoreid a7 + call4 esp_pm_trace_exit +#endif // CONFIG_PM_TRACE + + RET(16) +#endif // CONFIG_FREERTOS_SYSTICK_USES_CCOUNT + + /* +********************************************************************************************************** +* _frxt_tick_timer_init +* void _frxt_tick_timer_init(void) +* +* Initialize timer and timer interrrupt handler (_xt_tick_divisor_init() has already been been called). +* Callable from C (obeys ABI conventions on entry). +* +********************************************************************************************************** +*/ +#ifdef CONFIG_FREERTOS_SYSTICK_USES_CCOUNT + .globl _frxt_tick_timer_init + .type _frxt_tick_timer_init,@function + .align 4 +_frxt_tick_timer_init: + + ENTRY(16) + + + /* Set up the periodic tick timer (assume enough time to complete init). */ + #ifdef XT_CLOCK_FREQ + movi a3, XT_TICK_DIVISOR + #else + movi a2, _xt_tick_divisor + l32i a3, a2, 0 + #endif + rsr a2, CCOUNT /* current cycle count */ + add a2, a2, a3 /* time of first timer interrupt */ + wsr a2, XT_CCOMPARE /* set the comparator */ + + /* + Enable the timer interrupt at the device level. Don't write directly + to the INTENABLE register because it may be virtualized. + */ + #ifdef __XTENSA_CALL0_ABI__ + movi a2, XT_TIMER_INTEN + call0 xt_ints_on + #else + movi a6, XT_TIMER_INTEN + movi a3, xt_ints_on + callx4 a3 + #endif + + RET(16) +#endif // CONFIG_FREERTOS_SYSTICK_USES_CCOUNT + +/* +********************************************************************************************************** +* DISPATCH THE HIGH READY TASK +* void _frxt_dispatch(void) +* +* Switch context to the highest priority ready task, restore its state and dispatch control to it. +* +* This is a common dispatcher that acts as a shared exit path for all the context switch functions +* including vPortYield() and vPortYieldFromInt(), all of which tail-call this dispatcher +* (for windowed ABI vPortYieldFromInt() calls it indirectly via _frxt_int_exit() ). +* +* The Xtensa port uses different stack frames for solicited and unsolicited task suspension (see +* comments on stack frames in xtensa_context.h). This function restores the state accordingly. +* If restoring a task that solicited entry, restores the minimal state and leaves CPENABLE clear. +* If restoring a task that was preempted, restores all state including the task's CPENABLE. +* +* Entry: +* pxCurrentTCB points to the TCB of the task to suspend, +* Because it is tail-called without a true function entrypoint, it needs no 'entry' instruction. +* +* Exit: +* If incoming task called vPortYield() (solicited), this function returns as if from vPortYield(). +* If incoming task was preempted by an interrupt, this function jumps to exit dispatcher. +* +********************************************************************************************************** +*/ + .globl _frxt_dispatch + .type _frxt_dispatch,@function + .align 4 +_frxt_dispatch: + + #ifdef __XTENSA_CALL0_ABI__ + call0 vTaskSwitchContext // Get next TCB to resume + movi a2, pxCurrentTCB + getcoreid a3 + addx4 a2, a3, a2 + #else + call4 vTaskSwitchContext // Get next TCB to resume + movi a2, pxCurrentTCB + getcoreid a3 + addx4 a2, a3, a2 + #endif + l32i a3, a2, 0 + l32i sp, a3, TOPOFSTACK_OFFS /* SP = next_TCB->pxTopOfStack; */ + s32i a3, a2, 0 + + /* Determine the type of stack frame. */ + l32i a2, sp, XT_STK_EXIT /* exit dispatcher or solicited flag */ + bnez a2, .L_frxt_dispatch_stk + +.L_frxt_dispatch_sol: + + /* Solicited stack frame. Restore minimal context and return from vPortYield(). */ + l32i a3, sp, XT_SOL_PS + #ifdef __XTENSA_CALL0_ABI__ + l32i a12, sp, XT_SOL_A12 + l32i a13, sp, XT_SOL_A13 + l32i a14, sp, XT_SOL_A14 + l32i a15, sp, XT_SOL_A15 + #endif + l32i a0, sp, XT_SOL_PC + #if XCHAL_CP_NUM > 0 + /* Ensure wsr.CPENABLE is complete (should be, it was cleared on entry). */ + rsync + #endif + /* As soons as PS is restored, interrupts can happen. No need to sync PS. */ + wsr a3, PS + #ifdef __XTENSA_CALL0_ABI__ + addi sp, sp, XT_SOL_FRMSZ + ret + #else + retw + #endif + +.L_frxt_dispatch_stk: + + #if XCHAL_CP_NUM > 0 + /* Restore CPENABLE from task's co-processor save area. */ + movi a3, pxCurrentTCB /* cp_state = */ + getcoreid a2 + addx4 a3, a2, a3 + l32i a3, a3, 0 + l32i a2, a3, CP_TOPOFSTACK_OFFS /* StackType_t *pxStack; */ + l16ui a3, a2, XT_CPENABLE /* CPENABLE = cp_state->cpenable; */ + wsr a3, CPENABLE + #endif + + /* Interrupt stack frame. Restore full context and return to exit dispatcher. */ + call0 _xt_context_restore + + /* In Call0 ABI, restore callee-saved regs (A12, A13 already restored). */ + #ifdef __XTENSA_CALL0_ABI__ + l32i a14, sp, XT_STK_A14 + l32i a15, sp, XT_STK_A15 + #endif + + #if XCHAL_CP_NUM > 0 + /* Ensure wsr.CPENABLE has completed. */ + rsync + #endif + + /* + Must return via the exit dispatcher corresponding to the entrypoint from which + this was called. Interruptee's A0, A1, PS, PC are restored and the interrupt + stack frame is deallocated in the exit dispatcher. + */ + l32i a0, sp, XT_STK_EXIT + ret + + +/* +********************************************************************************************************** +* PERFORM A SOLICTED CONTEXT SWITCH (from a task) +* void vPortYield(void) +* +* This function saves the minimal state needed for a solicited task suspension, clears CPENABLE, +* then tail-calls the dispatcher _frxt_dispatch() to perform the actual context switch +* +* At Entry: +* pxCurrentTCB points to the TCB of the task to suspend +* Callable from C (obeys ABI conventions on entry). +* +* Does not return to caller. +* +********************************************************************************************************** +*/ + .globl vPortYield + .type vPortYield,@function + .align 4 +vPortYield: + + #ifdef __XTENSA_CALL0_ABI__ + addi sp, sp, -XT_SOL_FRMSZ + #else + entry sp, XT_SOL_FRMSZ + #endif + + rsr a2, PS + s32i a0, sp, XT_SOL_PC + s32i a2, sp, XT_SOL_PS + #ifdef __XTENSA_CALL0_ABI__ + s32i a12, sp, XT_SOL_A12 /* save callee-saved registers */ + s32i a13, sp, XT_SOL_A13 + s32i a14, sp, XT_SOL_A14 + s32i a15, sp, XT_SOL_A15 + #else + /* Spill register windows. Calling xthal_window_spill() causes extra */ + /* spills and reloads, so we will set things up to call the _nw version */ + /* instead to save cycles. */ + movi a6, ~(PS_WOE_MASK|PS_INTLEVEL_MASK) /* spills a4-a7 if needed */ + and a2, a2, a6 /* clear WOE, INTLEVEL */ + addi a2, a2, XCHAL_EXCM_LEVEL /* set INTLEVEL */ + wsr a2, PS + rsync + call0 xthal_window_spill_nw + l32i a2, sp, XT_SOL_PS /* restore PS */ + wsr a2, PS + #endif + + rsil a2, XCHAL_EXCM_LEVEL /* disable low/med interrupts */ + + #if XCHAL_CP_NUM > 0 + /* Save coprocessor callee-saved state (if any). At this point CPENABLE */ + /* should still reflect which CPs were in use (enabled). */ + call0 _xt_coproc_savecs + #endif + + movi a2, pxCurrentTCB + getcoreid a3 + addx4 a2, a3, a2 + l32i a2, a2, 0 /* a2 = pxCurrentTCB */ + movi a3, 0 + s32i a3, sp, XT_SOL_EXIT /* 0 to flag as solicited frame */ + s32i sp, a2, TOPOFSTACK_OFFS /* pxCurrentTCB->pxTopOfStack = SP */ + + #if XCHAL_CP_NUM > 0 + /* Clear CPENABLE, also in task's co-processor state save area. */ + l32i a2, a2, CP_TOPOFSTACK_OFFS /* a2 = pxCurrentTCB->cp_state */ + movi a3, 0 + wsr a3, CPENABLE + beqz a2, 1f + s16i a3, a2, XT_CPENABLE /* clear saved cpenable */ +1: + #endif + + /* Tail-call dispatcher. */ + call0 _frxt_dispatch + /* Never reaches here. */ + + +/* +********************************************************************************************************** +* PERFORM AN UNSOLICITED CONTEXT SWITCH (from an interrupt) +* void vPortYieldFromInt(void) +* +* This calls the context switch hook (removed), saves and clears CPENABLE, then tail-calls the dispatcher +* _frxt_dispatch() to perform the actual context switch. +* +* At Entry: +* Interrupted task context has been saved in an interrupt stack frame at pxCurrentTCB->pxTopOfStack. +* pxCurrentTCB points to the TCB of the task to suspend, +* Callable from C (obeys ABI conventions on entry). +* +* At Exit: +* Windowed ABI defers the actual context switch until the stack is unwound to interrupt entry. +* Call0 ABI tail-calls the dispatcher directly (no need to unwind) so does not return to caller. +* +********************************************************************************************************** +*/ + .globl vPortYieldFromInt + .type vPortYieldFromInt,@function + .align 4 +vPortYieldFromInt: + + ENTRY(16) + + #if XCHAL_CP_NUM > 0 + /* Save CPENABLE in task's co-processor save area, and clear CPENABLE. */ + movi a3, pxCurrentTCB /* cp_state = */ + getcoreid a2 + addx4 a3, a2, a3 + l32i a3, a3, 0 + + l32i a2, a3, CP_TOPOFSTACK_OFFS + + rsr a3, CPENABLE + s16i a3, a2, XT_CPENABLE /* cp_state->cpenable = CPENABLE; */ + movi a3, 0 + wsr a3, CPENABLE /* disable all co-processors */ + #endif + + #ifdef __XTENSA_CALL0_ABI__ + /* Tail-call dispatcher. */ + call0 _frxt_dispatch + /* Never reaches here. */ + #else + RET(16) + #endif + +/* +********************************************************************************************************** +* _frxt_task_coproc_state +* void _frxt_task_coproc_state(void) +* +* Implements the Xtensa RTOS porting layer's XT_RTOS_CP_STATE function for FreeRTOS. +* +* May only be called when a task is running, not within an interrupt handler (returns 0 in that case). +* May only be called from assembly code by the 'call0' instruction. Does NOT obey ABI conventions. +* Returns in A15 a pointer to the base of the co-processor state save area for the current task. +* See the detailed description of the XT_RTOS_ENTER macro in xtensa_rtos.h. +* +********************************************************************************************************** +*/ +#if XCHAL_CP_NUM > 0 + + .globl _frxt_task_coproc_state + .type _frxt_task_coproc_state,@function + .align 4 +_frxt_task_coproc_state: + + + /* We can use a3 as a scratchpad, the instances of code calling XT_RTOS_CP_STATE don't seem to need it saved. */ + getcoreid a3 + movi a15, port_xSchedulerRunning /* if (port_xSchedulerRunning */ + addx4 a15, a3,a15 + l32i a15, a15, 0 + beqz a15, 1f + movi a15, port_interruptNesting /* && port_interruptNesting == 0 */ + addx4 a15, a3, a15 + l32i a15, a15, 0 + bnez a15, 1f + + movi a15, pxCurrentTCB + addx4 a15, a3, a15 + l32i a15, a15, 0 /* && pxCurrentTCB != 0) { */ + + beqz a15, 2f + l32i a15, a15, CP_TOPOFSTACK_OFFS + ret + +1: movi a15, 0 +2: ret + +#endif /* XCHAL_CP_NUM > 0 */ diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/readme_xtensa.txt b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/readme_xtensa.txt new file mode 100644 index 0000000000..56dcc69656 --- /dev/null +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/readme_xtensa.txt @@ -0,0 +1,763 @@ + FreeRTOS Port for Xtensa Configurable and Diamond Processors + ============================================================ + + FreeRTOS Kernel Version 10.0.0 + + +Introduction +------------ + +This document describes the Xtensa port for FreeRTOS multitasking RTOS. +For an introduction to FreeRTOS itself, please refer to FreeRTOS +documentation. + +This port currently works with FreeRTOS kernel version 10.0.0. + + +Xtensa Configuration Requirements and Restrictions +-------------------------------------------------- + +The Xtensa configurable architecture supports a vast space of processor +features. This port supports all of them, including custom processor +extensions defined in the TIE language, with certain minimum +requirements. You must use Xtensa Tools to compile and link FreeRTOS and +your application for your Xtensa configuration. The port uses the Xtensa +Hardware Abstraction Layer (HAL) to adapt to your Xtensa configuration. +NOTE: It may be possible to build and run this with the open-source +xtensa-linux tools provided you have the correct overlay for your Xtensa +configuration. However, this has not been tested and is currently not +supported by Cadence. + +This port includes optional reentrancy support for the 'newlib' and +'xclib' C runtime libraries distributed with Xtensa Tools, providing +thread-safety on a per task basis (for use in tasks only, not interrupt +handlers). + +NOTE: At this time only 'newlib' and 'xclib' C libraries are supported +for thread safety. The 'uclibc' library is not reentrant and does not +provide thread safety at this time. However, if you are not concerned +with reentrancy then you can use any of these libraries. + +This port also includes a simple example application that may run on +a supported board or the Xtensa instruction set simulator (ISS). There +are also a couple of test programs used in maintaining the port, which +serve as additional examples. + +FreeRTOS for Xtensa configurable processors requires the following minimum +processor configuration options: +- Timer interrupt option with at least one interruptible timer. +- Interrupt option (implied by the timer interrupt option). +- Exception Architecture 2 (XEA2). Please note that XEA1 is NOT supported. + All 'Diamond', 'Xtensa 6', 'Xtensa LX' and 'Xtensa LX2' processors and + most 'Xtensa T1050' processors are configured with XEA2. +All Diamond processor cores meet these requirements and are supported. + +Minimal support for certain evaluation boards is provided via a board +independent XTBSP API implemented by a board specific library distributed +with the Xtensa Tools. This provides the board clock frequency and basic +polled drivers for the display and console device. Note that XTBSP +is not a tradtional RTOS "board support package" with RTOS specific +interrupt-driven drivers - it is not specific to any RTOS. Note that +FreeRTOS can run on any Xtensa or Diamond board without this board support +(a "raw" platform), but you will have to provide the clock frequency +and drivers for any on-board devices you want to use. + + +Installation +------------ + +The Xtensa port of FreeRTOS is available at this location: + + https://github.com/foss-xtensa/amazon-freertos + +This download includes the core FreeRTOS source and include files needed +to build the port. You can also download the official release of FreeRTOS +version 1.0.0 or later from this location: + + https://github.com/aws/amazon-freertos + +The Xtensa port files are currently not included in the official package. + +All source is provided along with a Makefile that works for any host +platform supported by Xtensa Tools (Windows, Linux). These instructions +are written for Windows users, but can easily be understood and adapted +to other host platforms. + +First install the FreeRTOS common package in a directory of your choosing. +The structure of that package will look like this: + + +|-- demos +| `-- cadence +| `-- sim +| |-- common +| | |-- application_code +| | | `-- cadence_code +| | `-- config_files +| `-- xplorer +`-- lib + |-- FreeRTOS + | `-- portable + | |-- Common + | |-- MemMang + | `-- XCC + | `-- Xtensa + `-- include + `-- private + +The Xtensa Tools are available from Cadence as part of a processor +license. Be sure you have installed the Xtensa Tools and your processor +configuration. + + +Building FreeRTOS for Xtensa +---------------------------- + +To build the FreeRTOS library and the example programs, go into the +directory 'demos/cadence/sim' and use the makefile in that directory. +"make all" will build all the examples. There is another makefile in +the 'lib/FreeRTOS/portable/XCC/Xtensa' directory that builds just the +FreeRTOS library. + +By default, you will build for the Xtensa instruction set simulator. If +you have a supported emulation board, you can build to run on that. You +can also build to run on a raw Xtensa core with no board support, a +good starting point for supporting your own target platform. Cadence +recommends doing functional development on the simulator because it +is easier to debug with, then move to a board if/when you need to test +hardware drivers or real-time performance. + +The provided makefile simplifies building FreeRTOS and the example +for your Xtensa configuration and platform (ISS, board, etc.). There +are detailed instructions in the comments at the top of the makefile. + +The makefiles work on Windows and Linux and support incremental builds. +The build for each Xtensa configuration and target platform is placed in +a subdirectory so several core and platform builds can co-exist even with +incremental rebuilds. You may specify the root of the build area (if tou +want it to be elsewhere than under the source tree) by defining BLDROOT +either in the make command or your shell environment. + + +Building the FreeRTOS Library +----------------------------- + +First, be sure you have installed Xtensa Tools and your processor +configuration, and be sure that Xtensa Tools are in your search path. +You can use xt-make, which comes with the Xtensa Tools, to run the +makefiles. + +Change directories to the Xtensa port directory: + +> cd lib/FreeRTOS/portable/XCC/Xtensa + +Now build the FreeRTOS RTOS as a library (libfreertos.a) as follows: + +> xt-make + +which by default builds for the simulator (TARGET=sim), or: + +> xt-make TARGET=board + +which builds for a supported board. Note that the board type does not +need to be specified when building the FreeRTOS library. + +If you are building for an Xtensa processor configuration that is not the +default you selected when you installed Xtensa Tools, you need to define the +environment variable XTENSA_CORE. If your configuration is not in the +default registry you selected when you installed Xtensa Tools, you also +need to define the environment variable XTENSA_SYSTEM. See tools manuals. +You can avoid defining these in your environment if you pass the variables +you need to redefine into xt-make as follows: + +> xt-make XTENSA_CORE= XTENSA_SYSTEM= ... + +There are more details about build options in the comment in the Makefile. + +After the library has been built, you must link your application with this +library in order to use FreeRTOS. + + +Building the FreeRTOS Examples +------------------------------ + +The provided examples are designed to run on the Xtensa instruction set +simulator (ISS) or a supported evaluation board programmed with your +Xtensa processor configuration. + +To build the examples for the default platform (simulator): + +> cd demos/cadence/sim + +> xt-make all + +which is the same as + +> xt-make all TARGET=sim + +The boards currently supported are the Xilinx ML605 and KC705 FPGA +development boards. To target these boards, type + +> xt-make all TARGET=ml605 + +or + +> xt-make all TARGET=kc705 + +To build in a location other than the default, specify the new location +using the BLDROOT variable. Note that this makefile will invoke the +FreeRTOS library build makefile automatically, passing on the relevant +parameters based on what you specified. + +You can override the default compilation options by specifying the new +options via CFLAGS. For example: + +> xt-make all TARGET=sim CFLAGS="-O2 -Os -g" + +This compiles the examples and links them with the FreeRTOS library +libfreertos.a and the appropriate linker-support package (LSP) for your +target platform (you can override the LSP by adding LSP= to the +xt-make command line). The resulting ELF files can be downloaded and +executed on the target. The example binaries appear in the platform +specific subdirectory described earlier. + +To build your application with thread-safe C library support, you +need to make certain modifications to the application to plug in and +invoke the reentrancy support. This allows each task to use the library +without interference with other tasks (it is not safe for interrupt +handlers to call the C library). + +First, you must define + + XT_USE_THREAD_SAFE_CLIB + +to a nonzero value either in xtensa_config.h or on the compiler's command +line. Note that the default xtensa_config.h provided with this port does +define this to 1 if either newlib or xclib is detected. + +Then, you must also make sure to allocate extra space on the stack for +each task that will use the C library reentrant functions. This extra +space is to be allocated over and above the actual stack space required +by the task itself. The define + + XT_STACK_EXTRA_CLIB + +specifies the amount of extra space to be added on to the stack to allow +saving the context for the C library as well as the coprocessors if any. +E.g. if your task requires 2000 bytes of stack space, you must allocate +(2000 + XT_STACK_EXTRA_CLIB) bytes for the stack. + + +IMPORTANT NOTE +-------------- + +The header file FreeRTOS.h, which is a part of the core FreeRTOS sources, +includes if thread safety for the C libraries is enabled. For +xclib, this file exists in and so is reported as missing. +To work around this, the makefiles supplied with this port will copy the +reent.h header into the build directory during the build process. If you +use a different build process, then you must make sure to copy this file +to a location that is included in the list of include paths. This can be +the build directory or the directory that contains the Xtensa port source +files. + + +Running or Debugging an Application +----------------------------------- + +To execute the example application on the simulator: + +> xt-run [--turbo] example.exe + +The option --turbo provides much faster, but non-cycle-accurate simulation +(the --turbo option is only available with Xtensa Tools version 7 or later). + + +To execute on the simulator using the Xplorer GUI based debugger: + +> xplorer --debug example.exe + + +To execute on a supported evaluation board, download example.exe per +instructions in the tools manuals. Be sure the board has been programmed +with the correct configuration and is set up to boot from RAM and debug +a downloaded program! Optionally you may connect a terminal or terminal +emulator to the serial port on the board with settings as described in +the board user manual, and see the output of printf on the terminal. + +To obtain I/O on a "raw" platform such as an unsupported board, you need +to provide low level I/O drivers (eg. inbyte() and outbyte() for character +I/O if you want to use printf etc.). You can run "raw" executables on +any Xtensa platform, including simulator and any board, but you will not +see any behavior specific to the platform (eg. display, printed output, +stopping simulation at end of program). You can, while debugging, use a +debugger mechanism called GDBIO to obtain basic I/O. To use GDBIO, link +with the gdbio LSP. Refer to Xtensa tools documentation for details. + + +Task Stack Sizes +---------------- + +The application must ensure that every task has enough space for its +stack. Each task needs enough space for its own use, its own interrupt +stack frame (defined in xtensa_context.h) and space to save coprocessor +state, if any. Several factors influence the size of the stack required, +including the compiler optimization level and the use of the C library. +Calls to standard output functions such as printf() can use up a lot of +stack space. The tool xt-stack-usage is helpful in determining safe stack +sizes for your application. + +Some macros are provided in xtensa_config.h to help determine the stack +size for tasks that do and do not use the C library. Use these as the +basis for each task's stack size. They are minimum requirements taking +into account your configuration and use of the C library. In particular, +the define + + XT_STACK_MIN_SIZE + +defines the minimum stack size for any task. Be very careful if you try +to use a stack size smaller than this minimum. Stack overruns can cause +all kinds of hard-to-debug errors. It is recommended that you enable the +FreeRTOS stack checking features during development. + +WARNING: The newlib printf() function uses a lot of stack space. Be very +careful in using it. Optionally you can use the 'libxtutil' library for +output - it implements a subset of printf() that has smaller code size +and uses far less stack space. More information about this library is in +the Xtensa Tools documentation. + + +Interrupt Stack +--------------- + +Beginning with port version 1.2, the port uses a separate interrupt stack +for handling interrupts. Thus, it is no longer necessary for each task to +reserve space on its stack to handle interrupts. The size of the interrupt +stack is controlled by the parameter "configISR_STACK_SIZE" defined in +FreeRTOSConfig.h. Define this carefully to match your system requirements. + + +Assembler / Compiler Switches +----------------------------- + +The following are compiler switches are used by the provided +Makefile in building the FreeRTOS library and example application. +These can be modified by editing the Makefile or by overriding the +CFLAGS variable in the make command line, for example: + +> xt-make CFLAGS="-O2 -DXT_USE_THREAD_SAFE_CLIB" + + -g Specifies debug information. + -c Specifies object code generation. + -On Sets compiler optimization level n (default -O0). + -mlongcalls Allows assembler and linker to convert call + instructions to longer indirect call sequences + when target is out of range. + -x assembler-with-cpp Passes .s and .S files through C preprocessor. + -Dmacro Define a preprocessor macro with no value. + -Dmacro=value Define a preprocessor macro with a value. + +See the compiler / linker documentation for a full list of switches and +their use. + +Many definitions can be provided at compile-time via the -D option +without editing the source code. Here are some of the more useful ones: + + XT_USE_THREAD_SAFE_CLIB Enable support for the reentrancy to provide + thread-safety for the newlib and xclib libraries + supplied with Xtensa Tools. Default ON. + + Note, the follwing defines are unique to the Xtensa port so have names + beginning with "XT_". + + XT_SIMULATOR Set this if building to run on the simulator. + Takes advantage of certain simulator control + and reporting facilities, and adjusts timing + of periodic tick to provide a more acceptable + performance in simulation (see XT_CLOCK_FREQ). + Set by default unless PLATFORM is overridden. + + XT_BOARD Set this if building for a supported board. + Be sure to specify the correct LSP for the + board. See the example makefile for usage. + + XT_CLOCK_FREQ=freq Specifies the target processor's clock + frequency in Hz. Used primarily to set the + timer that generates the periodic interrupt. + Defaults are provided and may be edited in + xtensa_timer.h (see comments there also). + Default for simulator provides more acceptable + performance, but cannot provide real-time + performance due to variation in simulation + speed per host platform and insufficient + cycles between interrupts to process them. + Supported board platforms by default leave + this undefined and compute the clock frequency + at initialization unless this is explicitly + defined. + + XT_TICK_PER_SEC=n Specifies the frequency of the periodic tick. + + XT_TIMER_INDEX=n Specifies which timer to use for periodic tick. + Set this if your Xtensa processor configuration + provides more than one suitable timer and you + want to override the default. See xtensa_timer.h . + + XT_INTEXC_HOOKS Enables hooks in interrupt vector handlers + to support dynamic installation of exception + and interrupt handlers. Disabled by default. + + XT_USE_OVLY Enable code overlay support. It uses a mutex, + hence configUSE_MUTEX must be enabled. This + option is currently unsupported. + + XT_USE_SWPRI Enable software prioritization of interrupts. + Enabling this will prioritize interrupts with + higher bit numbers over those with lower bit + numbers at the same level. This works only for + low and medium priority interrupts that can be + dispatched to C handlers. + + +Register Usage and Stack Frames +------------------------------- + +The Xtensa architecture specifies two ABIs that determine how the general +purpose registers a0-a15 are used: the standard windowed ABI use with +the Xtensa windowed register file architecture, and the optional and +more conventional Call0 ABI (required for Xtensa configurations without +a windowed register file). + +Xtensa processors may have other special registers (including co-processor +registers and other TIE "states") that are independent of this choice +of ABI. See Xtensa documentation for more details. + +In the windowed ABI the registers of the current window are used as follows: + a0 = return address + a1 = stack pointer (alias sp) + a2 = first argument and result of call (in simple cases) + a3-7 = second through sixth arguments of call (in simple cases). + Note that complex or large arguments are passed on the + stack. Details are in the Xtensa Tools manuals. + a8-a15 = available for use as temporaries. +There are no callee-save registers. The windowed hardware automatically +saves registers a0-a3 on a call4, a0-a8 on a call8, a0-a12 on a call12, +by rotating the register window. Hardware triggers window overflow and +underflow exceptions as necessary when registers outside the current +window need to be spilled to preallocated space in the stack frame, or +restored. Complete details are in the Xtensa manuals. The entire windowed +register file is saved and restored on interrupt or task context switch. + +The Call0 ABI does not make use of register windows, relying instead +on a fixed set of 16 registers without window rotation. +The Call0 ABI is more conventional and uses registers as follows: + a0 = return address + a1 = stack pointer (alias sp) + a2 = first argument and result of call (in simple cases) + a3-7 = second through sixth arguments of call (in simple cases). + Note that complex or large arguments are passed on the + stack. Details are in the Xtensa Tools manuals. + a8-a11 = scratch. + a12-a15 = callee-save (a function must preserve these for its caller). +On a FreeRTOS API call, callee-save registers are saved only when a task +context switch occurs, and other registers are not saved at all (the caller +does not expect them to be preserved). On an interrupt, callee-saved +registers might only be saved and restored when a task context-switch +occurs, but all other registers are always saved and restored. + +An Xtensa processor has other special registers independent of the ABI, +depending on the configuration (including co-processor registers and other +TIE state) that are part of the task context. FreeRTOS preserves all such +registers over an unsolicited context-switch triggered by an interrupt. +However it does NOT preserve these over a solicited context-switch during +a FreeRTOS API call. This bears some explanation. These special registers +are either ignored by the compiler or treated as caller-saved, meaning +that if kept "live" over a function call (ie. need to be preserved) +they must be saved and restored by the caller. Since solicited entry to +FreeRTOS is always made by a function call, FreeRTOS assumes the caller +has saved any of these registers that are "live". FreeRTOS avoids a lot +of overhead by not having to save and restore every special register +(there can be many) on every solicited context switch. + +As a consequence, the application developer should NOT assume that special +registers are preserved over a FreeRTOS API call such as vTaskDelay(). +If multiple tasks use a register, the caller must save and restore it. + +The saved context stack frames for context switches that occur as +a result of interrupt handling (interrupt frame) or from task-level +API calls (solicited frame) are described in human readable form in +xtensa_context.h . All suspended tasks have one of these two types +of stack frames. The top of the suspended task's stack is pointed to +by pxCurrentTCB->pxTopOfStack. A special location common to both stack +frames differentiates solicited and interrupt stack frames. + + +Improving Performance, Footprint, or Ease of Debugging +------------------------------------------------------ + +By default FreeRTOS for Xtensa is built with debug (-g) and without +compiler optimizations (-O0). This makes debugging easier. Of course, +-O0 costs performance and usually also increases stack usage. To make +FreeRTOS run faster you can change the Makefile to enable the desired +optimizations or set a predefined optimization level (-O) . + +Maximum performance is achieved with -O3 -ipa, but that might increase +the footprint substantially. A good compromise is -O2. See the compiler +manual for details. + +Minimal footprint is achieved by optimizing for space with -Os, at the +cost of some performance. See the compiler manual for details. + +The Xtensa architecture port-specific assembly files are coded with no +file-scope labels inside functions (all labels inside functions begin with +".L"). This allows a profiler to accurately associate an address with a +function, and also allows the debugger's stack trace to show the correct +function wherever the program counter is within that function. However +there are some tradeoffs in debugging. Local (".L") labels are not +visible to the debugger, so the following limitations may be observed +during debugging: +- You cannot set a breakpoint on a local label inside a function. +- Disassembly will show the entire function, but will get out of sync and + show incorrect opcodes if it crosses any padding before an aligned local + branch target (".L" label, not ".Ln"). Restart disassembly specifying an + address range explicitly between points where there is padding. +Since FreeRTOS is provided in source form, it is not difficult to remove +the ".L" and ".Ln" prefixes from local labels if you want them visible. +They can also be made visible by passing the '-L' option to the assembler +and linker (see the assembler and linker manuals for details). + + +Interrupt and Exception Handling +-------------------------------- + +FreeRTOS provides a complete set of efficient exception and first-level +interrupt handlers installed at the appropriate exception and interrupt +vector locations. The Xtensa architecture supports several different +classes of exceptions and interrupts. Being a configurable architecture, +many of these are optional, and the vector locations are determined by +your processor configuration. (Note that Diamond cores are pre-configured +with specific vector locations.) The handlers provided use conditional +compilation to adapt to your processor configuration and include only +the code that is needed. + +Xtensa vector locations may reside almost anywhere, including in ROM. +The amount of code space available at each of these locations is +often very small (e.g. due to following vectors). A small stub of +code installed at the vector jumps to the corresponding handler, +usually in RAM. The exception and interrupt handlers are defined in +xtensa_vectors.S. They are not specific to FreeRTOS, but call into +FreeRTOS where appropriate via macros defined in xtensa_rtos.h . + +The handlers provided for low and medium priority interrupts are just +dispatchers that save relevant state and call user-definable handlers. +See the files xtensa_vectors.S and xtensa_api.h for more details of how +to create and install application-specific user interrupt handlers. +Similarly, user-defined handlers can be installed for exceptions (other +than a few which are always handled by the OS). + +The high priority interrupt handlers provided may be considered templates +into which the application adds code to service specific interrupts. +The places where application handlers should be inserted are tagged with +the comment "USER_EDIT" in xtensa_vectors.S. + +This FreeRTOS port supports strict priority-based nesting of interrupts. +An interrupt may only nest on top of one of strictly lower priority. +Equal priority interrupts concurrently pending are handled in an +application-defined sequence before any lower priority interrupts +are handled. During interrupt and exception handling, the processor's +interrupt level (PS.INTLEVEL) is used to control the interrupt priority +level that can be accepted; interrupt sources are not controlled +individually by FreeRTOS (the application is free to access the INTENABLE +register directly to enable/disable individual interrupts, eg. using +Xtensa HAL services). This approach provides the most deterministic +bounds on interrupt latency (for a given priority) and stack depth. + +Software prioritization of interrupts at the same priority is controlled +by the definition of XT_USE_SWPRI. See above for a description of this +parameter. + +The following subsections describe the handling of each class of exception +and interrupt in more detail. Many have nothing to do with FreeRTOS but +are mentioned because there is code to handle them in xtensa_vectors.S. + +User Exception and Interrupt Handler (Low/Medium Priority): + + All Xtensa 'general exceptions' come to the user, kernel, or double + exception vector. The exception type is identified by the EXCCAUSE + special register (level 1 interrupts are one particular cause of a + general exception). This port sets up PS to direct all such exceptions + to the user vector. Exceptions taken at the other two vectors usually + indicate a kernel or application bug. + + Level 1 interrupts are identified at the beginning of the handler + and are dispatched to a dedicated handler. Then, syscall and alloca + exceptions are identified and dispatched to special handlers described + below. After this, coprocessor exceptions are identified and dispatched + to the coprocessor handler. + + Any remaining exceptions are processed as follows: + + Having allocated the exception stack frame, the user exception handler + saves the current task state and sets up a C environment and enables + the high-priority class of interrupts (which do not interact with + FreeRTOS), then reads EXCCAUSE and uses the cause (number) to index + into a table of user-specified handlers. The correct handler is then + called. If the handler returns, the context is restored and control is + returned to the code that caused the exception. The user-defined handler + may alter the saved context, or any other system state, that allows the + faulting instruction to be retried. + + If the cause is a level 1 (low-priority) or medium-priority interrupt, + the handler enables all interrupts above that priority level after + saving the task context. It then sets up the environment for C code + and then calls the handler (found in the handler table) for the + interrupt number. If the user has not specified a handler, then the + default handler will be called, which will terminate the program. + + If the interrupt is for the system timer, it calls a special interrupt + handler for the system timer tick, which calls _frxt_timer_int then + clears its bit from the mask. This interrupt cannot be hooked by the + user-defined handler. + + Finally, the handler calls _frxt_int_exit to allow FreeRTOS to perform + any scheduling necessary and return either to the interrupted task + or another. + + If software prioritization is enabled, the handler will re-enable all + interrupts at the same level that are numerically higher than the current + one, before calling the user handler. This allows a higher priority + interrupt to pre-empt the lower priority handler. + +Medium Priority Interrupt Handlers: + + Medium priority interrupts are those at levels 2 up to XCHAL_EXCM_LEVEL, + a configuration-specific maximum interrupt level affected by the global + 'exception mode' bit in the processor status word (PS.EXCM). + Interrupt levels above XCHAL_EXCM_LEVEL are of the high-priority class. + The Xtensa hardware documentation considers medium priority interrupts + to be a special case of high-priority interrupts, but from a software + perspective they are very different. + + Dispatch of medium-priority interrupts is discussed in the section + above. + +High Priority Interrupt Handlers: + + High priority interrupts are those strictly above XCHAL_EXCM_LEVEL, + a configuration-specific maximum interrupt level affected by the + global 'exception mode' bit in the processor status word (PS.EXCM). + High priority handlers may not directly interact with FreeRTOS at all, + and are described here only for the sake of completeness. They must + be coded in assembler (may not be coded in C) and are intended to be + used for handling extremely high frequency hardware events that need + to be handled in only a few cycles. A high priority interrupt handler + may trigger a software interrupt at a medium or low priority level to + occasionally signal FreeRTOS. Please see Xtensa documentation. + + There is a separate vector and a few special registers for each high + priority interrupt, providing for fast dispatch and efficient nesting + on top of lower priority interrupts. Handlers are templates included + only for the vectors that exist in your Xtensa processor configuration. + These templates are written for only one interrupt per high priority + level to minimize latency servicing very fast time-critical interrupts. + The vector code jumps to the corresponding first-level interrupt handler, + which then executes application-provided assembler code before returning + quickly to the interrupted task or lower priority handler. + +Kernel Exception Handler: + + Kernel mode is not used in this port of FreeRTOS, and therefore kernel + exceptions should not happen. A stub is provided for the vector that + triggers the debugger (if connected) or calls _xt_panic to freeze the + processor should a kernel exception occur. + +Alloca Exception Handler: + + Alloca exceptions are generated by the 'movsp' instruction, which + is used only in the windowed ABI. Its purpose is to allocate some + space on top of the stack. Because the window hardware may have + spilled some registers to the 16 byte "base save" area below the + stack pointer, it is necessary to protect those values. The alloca + handler accomplishes this quickly without setting up an interrupt + frame or entering FreeRTOS, by emulating a register underflow and + re-executing 'movsp'. + +Syscall Exception Handler: + + Syscall exceptions are generated by a 'syscall' instruction. + The windowed ABI specifies that executing this instruction with + a value of zero in register a2 must spill any unsaved registers + in the windowed register file to their pre-determined locations + on the caller's stack. The handler does exactly that, and skips + over the 'syscall' instruction before returning to the caller. + If a2 is non-zero, the handler returns a2 == -1 to the caller. + +Co-Processor Exception Handler: + + A co-processor exception is generated when a task accesses a + co-processor that it does not "own". Ownership represents which + task's state is currently in the co-processor. Co-processors are + context-switched "lazily" (on demand) only when a non-owning task + uses a co-processor instruction, otherwise a task retains ownership + even when it is preempted from the main processor. The co-processor + exception handler performs the context-switch and manages ownership. + + Co-processors may not be used by any code outside the context of a + task. A co-processor exception triggered by code that is not part + of a running task is a fatal error and FreeRTOS for Xtensa will panic. + This restriction is intended 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. + +Debug Exception Handler: + + A debug exception is caused as a result of running code, such as by + a 'break' instruction or hardware breakpoints and watchpoints, or + as a result of an external debug interrupt, such as from an OCD based + debugger or multiprocessor debug events ("breakin/breakout"). If the + processor is running in OCD mode under control of an OCD-based debugger, + the trigger event immediately halts the processor and gives control to + the OCD debugger. Otherwise control is transferred to the debug vector. + The debug vector handler calls the simulator if running on the ISS, + which then takes control and interacts with any attached debugger. + If running on hardware and not in OCD mode, debug exceptions are not + expected, so the debug handler calls _xt_panic to freeze the processor. + +Double Exception Handler: + + A double exception is a general exception that happens while the + processor is in exception mode (PS.EXCM set), and thus indicates a + bug in kernel code. The double exception vector handler triggers + the debugger (if connected) or calls _xt_panic to freeze the + processor. + +Window Overflow and Underflow Exception Handlers: + + Window overflow and underflow handlers are required for use of the + windowed ABI. Each has its own dedicated vector and highly optimized + code that is independent of OS. See Xtensa documentation for details. + +Hooks for Dynamic Installation of Handlers: + + Optional hooks are provided in the user exception and low level + interrupt handler and all medium and high priority interrupt handlers, + to dynamically install a handler function (which may be coded in C, + unless in a high-priority interrupt handler). These hooks are enabled + and used by automatic regression tests, they are not part of a normal + FreeRTOS build. However an application is free to take advantage of + them. The interrupt/exception hooks are described in xtensa_rtos.h . + + It is recommended that the application not make use of these hooks, but + rather use xt_set_interrupt_handler() and xt_set_exception_handler() + to install application-specific handlers. This method is more convenient + and allows arguments to be passed to the handlers. Software prioritization + of interrupts works only with this method. See xtensa_api.h for details. + +Overlay Support + + Code overlays are currently not supported for FreeRTOS. This will be + supported in a future release. Make sure that the option XT_USE_OVLY is + never defined when building. + + +-End- diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/xt_asm_utils.h b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/xt_asm_utils.h new file mode 100644 index 0000000000..d4f25b79f7 --- /dev/null +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/xt_asm_utils.h @@ -0,0 +1,75 @@ +/* + * SPDX-FileCopyrightText: 2017, Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + * + * SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD + */ + +/* 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 diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/xtensa_context.S b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/xtensa_context.S new file mode 100644 index 0000000000..df0b2324d2 --- /dev/null +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/xtensa_context.S @@ -0,0 +1,665 @@ +/* + * 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 CONTEXT SAVE AND RESTORE ROUTINES + * + * Low-level Call0 functions for handling generic context save and restore of + * registers not specifically addressed by the interrupt vectors and handlers. + * Those registers (not handled by these functions) are PC, PS, A0, A1 (SP). + * Except for the calls to RTOS functions, this code is generic to Xtensa. + * + * Note that in Call0 ABI, interrupt handlers are expected to preserve the callee- + * save regs (A12-A15), which is always the case if the handlers are coded in C. + * However A12, A13 are made available as scratch registers for interrupt dispatch + * code, so are presumed saved anyway, and are always restored even in Call0 ABI. + * Only A14, A15 are truly handled as callee-save regs. + * + * Because Xtensa is a configurable architecture, this port supports all user + * generated configurations (except restrictions stated in the release notes). + * This is accomplished by conditional compilation using macros and functions + * defined in the Xtensa HAL (hardware adaptation layer) for your configuration. + * Only the processor state included in your configuration is saved and restored, + * including any processor state added by user configuration options or TIE. + */ + +/* Warn nicely if this file gets named with a lowercase .s instead of .S: */ +#define NOERROR # +NOERROR: .error "C preprocessor needed for this file: make sure its filename\ + ends in uppercase .S, or use xt-xcc's -x assembler-with-cpp option." + + +#include "xtensa_rtos.h" +#include "xtensa_context.h" +#include "xt_asm_utils.h" + +#ifdef XT_USE_OVLY +#include +#endif + + .text + +/******************************************************************************* + +_xt_context_save + + !! MUST BE CALLED ONLY BY 'CALL0' INSTRUCTION !! + +Saves all Xtensa processor state except PC, PS, A0, A1 (SP), A12, A13, in the +interrupt stack frame defined in xtensa_rtos.h. +Its counterpart is _xt_context_restore (which also restores A12, A13). + +Caller is expected to have saved PC, PS, A0, A1 (SP), A12, A13 in the frame. +This function preserves A12 & A13 in order to provide the caller with 2 scratch +regs that need not be saved over the call to this function. The choice of which +2 regs to provide is governed by xthal_window_spill_nw and xthal_save_extra_nw, +to avoid moving data more than necessary. Caller can assign regs accordingly. + +Entry Conditions: + A0 = Return address in caller. + A1 = Stack pointer of interrupted thread or handler ("interruptee"). + Original A12, A13 have already been saved in the interrupt stack frame. + Other processor state except PC, PS, A0, A1 (SP), A12, A13, is as at the + point of interruption. + If windowed ABI, PS.EXCM = 1 (exceptions disabled). + +Exit conditions: + A0 = Return address in caller. + A1 = Stack pointer of interrupted thread or handler ("interruptee"). + A12, A13 as at entry (preserved). + If windowed ABI, PS.EXCM = 1 (exceptions disabled). + +*******************************************************************************/ + + .global _xt_context_save + .type _xt_context_save,@function + .align 4 + .literal_position + .align 4 + +_xt_context_save: + + s32i a2, sp, XT_STK_A2 + s32i a3, sp, XT_STK_A3 + s32i a4, sp, XT_STK_A4 + s32i a5, sp, XT_STK_A5 + s32i a6, sp, XT_STK_A6 + s32i a7, sp, XT_STK_A7 + s32i a8, sp, XT_STK_A8 + s32i a9, sp, XT_STK_A9 + s32i a10, sp, XT_STK_A10 + s32i a11, sp, XT_STK_A11 + + /* + Call0 ABI callee-saved regs a12-15 do not need to be saved here. + a12-13 are the caller's responsibility so it can use them as scratch. + So only need to save a14-a15 here for Windowed ABI (not Call0). + */ + #ifndef __XTENSA_CALL0_ABI__ + s32i a14, sp, XT_STK_A14 + s32i a15, sp, XT_STK_A15 + #endif + + rsr a3, SAR + s32i a3, sp, XT_STK_SAR + + #if XCHAL_HAVE_LOOPS + rsr a3, LBEG + s32i a3, sp, XT_STK_LBEG + rsr a3, LEND + s32i a3, sp, XT_STK_LEND + rsr a3, LCOUNT + s32i a3, sp, XT_STK_LCOUNT + #endif + + #ifdef XT_USE_SWPRI + /* Save virtual priority mask */ + movi a3, _xt_vpri_mask + l32i a3, a3, 0 + s32i a3, sp, XT_STK_VPRI + #endif + + #if XCHAL_EXTRA_SA_SIZE > 0 || !defined(__XTENSA_CALL0_ABI__) + mov a9, a0 /* preserve ret addr */ + #endif + + 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 + + #if XCHAL_EXTRA_SA_SIZE > 0 + 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 */ + #endif + + #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 /* go back to spill register region */ + SPILL_ALL_WINDOWS /* place the live register windows there */ + 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 + + #if XCHAL_EXTRA_SA_SIZE > 0 || !defined(__XTENSA_CALL0_ABI__) + mov a0, a9 /* retrieve ret addr */ + #endif + + ret + +/******************************************************************************* + +_xt_context_restore + + !! MUST BE CALLED ONLY BY 'CALL0' INSTRUCTION !! + +Restores all Xtensa processor state except PC, PS, A0, A1 (SP) (and in Call0 +ABI, A14, A15 which are preserved by all interrupt handlers) from an interrupt +stack frame defined in xtensa_rtos.h . +Its counterpart is _xt_context_save (whose caller saved A12, A13). + +Caller is responsible to restore PC, PS, A0, A1 (SP). + +Entry Conditions: + A0 = Return address in caller. + A1 = Stack pointer of interrupted thread or handler ("interruptee"). + +Exit conditions: + A0 = Return address in caller. + A1 = Stack pointer of interrupted thread or handler ("interruptee"). + Other processor state except PC, PS, A0, A1 (SP), is as at the point + of interruption. + +*******************************************************************************/ + + .global _xt_context_restore + .type _xt_context_restore,@function + .align 4 + .literal_position + .align 4 +_xt_context_restore: + + #if XCHAL_EXTRA_SA_SIZE > 0 + /* + NOTE: Normally the xthal_restore_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 only assume a13 is preserved. + Future Xtensa tools releases might limit the regs that can be affected. + */ + mov a13, a0 /* preserve ret addr */ + addi a2, sp, XT_STK_EXTRA /* where to find it */ + # if XCHAL_EXTRA_SA_ALIGN > 16 + movi a3, -XCHAL_EXTRA_SA_ALIGN + and a2, a2, a3 /* align dynamically >16 bytes */ + # endif + call0 xthal_restore_extra_nw /* destroys a0,2,3,4,5 */ + mov a0, a13 /* retrieve ret addr */ + #endif + + #if XCHAL_HAVE_LOOPS + l32i a2, sp, XT_STK_LBEG + l32i a3, sp, XT_STK_LEND + wsr a2, LBEG + l32i a2, sp, XT_STK_LCOUNT + wsr a3, LEND + wsr a2, LCOUNT + #endif + + #ifdef XT_USE_OVLY + /* + If we are using overlays, this is a good spot to check if we need + to restore an overlay for the incoming task. Here we have a bunch + of registers to spare. Note that this step is going to use a few + bytes of storage below SP (SP-20 to SP-32) if an overlay is going + to be restored. + */ + l32i a2, sp, XT_STK_PC /* retrieve PC */ + l32i a3, sp, XT_STK_PS /* retrieve PS */ + l32i a4, sp, XT_STK_OVLY /* retrieve overlay state */ + l32i a5, sp, XT_STK_A1 /* retrieve stack ptr */ + _xt_overlay_check_map a2, a3, a4, a5, a6 + s32i a2, sp, XT_STK_PC /* save updated PC */ + s32i a3, sp, XT_STK_PS /* save updated PS */ + #endif + + #ifdef XT_USE_SWPRI + /* Restore virtual interrupt priority and interrupt enable */ + movi a3, _xt_intdata + l32i a4, a3, 0 /* a4 = _xt_intenable */ + l32i a5, sp, XT_STK_VPRI /* a5 = saved _xt_vpri_mask */ + and a4, a4, a5 + wsr a4, INTENABLE /* update INTENABLE */ + s32i a5, a3, 4 /* restore _xt_vpri_mask */ + #endif + + l32i a3, sp, XT_STK_SAR + l32i a2, sp, XT_STK_A2 + wsr a3, SAR + l32i a3, sp, XT_STK_A3 + l32i a4, sp, XT_STK_A4 + l32i a5, sp, XT_STK_A5 + l32i a6, sp, XT_STK_A6 + l32i a7, sp, XT_STK_A7 + l32i a8, sp, XT_STK_A8 + l32i a9, sp, XT_STK_A9 + l32i a10, sp, XT_STK_A10 + l32i a11, sp, XT_STK_A11 + + /* + Call0 ABI callee-saved regs a12-15 do not need to be restored here. + However a12-13 were saved for scratch before XT_RTOS_INT_ENTER(), + so need to be restored anyway, despite being callee-saved in Call0. + */ + l32i a12, sp, XT_STK_A12 + l32i a13, sp, XT_STK_A13 + #ifndef __XTENSA_CALL0_ABI__ + l32i a14, sp, XT_STK_A14 + l32i a15, sp, XT_STK_A15 + #endif + + ret + + +/******************************************************************************* + +_xt_coproc_init + +Initializes global co-processor management data, setting all co-processors +to "unowned". Leaves CPENABLE as it found it (does NOT clear it). + +Called during initialization of the RTOS, before any threads run. + +This may be called from normal Xtensa single-threaded application code which +might use co-processors. The Xtensa run-time initialization enables all +co-processors. They must remain enabled here, else a co-processor exception +might occur outside of a thread, which the exception handler doesn't expect. + +Entry Conditions: + Xtensa single-threaded run-time environment is in effect. + No thread is yet running. + +Exit conditions: + None. + +Obeys ABI conventions per prototype: + void _xt_coproc_init(void) + +*******************************************************************************/ + +#if XCHAL_CP_NUM > 0 + + .global _xt_coproc_init + .type _xt_coproc_init,@function + .align 4 + .literal_position + .align 4 +_xt_coproc_init: + ENTRY0 + + /* Initialize thread co-processor ownerships to 0 (unowned). */ + movi a2, _xt_coproc_owner_sa /* a2 = base of owner array */ + addi a3, a2, (XCHAL_CP_MAX*portNUM_PROCESSORS) << 2 /* a3 = top+1 of owner array */ + movi a4, 0 /* a4 = 0 (unowned) */ +1: s32i a4, a2, 0 + addi a2, a2, 4 + bltu a2, a3, 1b + + RET0 + +#endif + + +/******************************************************************************* + +_xt_coproc_release + +Releases any and all co-processors owned by a given thread. The thread is +identified by it's co-processor state save area defined in xtensa_context.h . + +Must be called before a thread's co-proc save area is deleted to avoid +memory corruption when the exception handler tries to save the state. +May be called when a thread terminates or completes but does not delete +the co-proc save area, to avoid the exception handler having to save the +thread's co-proc state before another thread can use it (optimization). + +Needs to be called on the processor the thread was running on. Unpinned threads +won't have an entry here because they get pinned as soon they use a coprocessor. + +Entry Conditions: + A2 = Pointer to base of co-processor state save area. + +Exit conditions: + None. + +Obeys ABI conventions per prototype: + void _xt_coproc_release(void * coproc_sa_base) + +*******************************************************************************/ + +#if XCHAL_CP_NUM > 0 + + .global _xt_coproc_release + .type _xt_coproc_release,@function + .align 4 + .literal_position + .align 4 +_xt_coproc_release: + ENTRY0 /* a2 = base of save area */ + + getcoreid a5 + movi a3, XCHAL_CP_MAX << 2 + mull a5, a5, a3 + movi a3, _xt_coproc_owner_sa /* a3 = base of owner array */ + add a3, a3, a5 + + addi a4, a3, XCHAL_CP_MAX << 2 /* a4 = top+1 of owner array */ + movi a5, 0 /* a5 = 0 (unowned) */ + + rsil a6, XCHAL_EXCM_LEVEL /* lock interrupts */ + +1: l32i a7, a3, 0 /* a7 = owner at a3 */ + bne a2, a7, 2f /* if (coproc_sa_base == owner) */ + s32i a5, a3, 0 /* owner = unowned */ +2: addi a3, a3, 1<<2 /* a3 = next entry in owner array */ + bltu a3, a4, 1b /* repeat until end of array */ + +3: wsr a6, PS /* restore interrupts */ + + RET0 + +#endif + + +/******************************************************************************* +_xt_coproc_savecs + +If there is a current thread and it has a coprocessor state save area, then +save all callee-saved state into this area. This function is called from the +solicited context switch handler. It calls a system-specific function to get +the coprocessor save area base address. + +Entry conditions: + - The thread being switched out is still the current thread. + - CPENABLE state reflects which coprocessors are active. + - Registers have been saved/spilled already. + +Exit conditions: + - All necessary CP callee-saved state has been saved. + - Registers a2-a7, a13-a15 have been trashed. + +Must be called from assembly code only, using CALL0. +*******************************************************************************/ +#if XCHAL_CP_NUM > 0 + + .extern _xt_coproc_sa_offset /* external reference */ + + .global _xt_coproc_savecs + .type _xt_coproc_savecs,@function + .align 4 + .literal_position + .align 4 +_xt_coproc_savecs: + + /* At entry, CPENABLE should be showing which CPs are enabled. */ + + rsr a2, CPENABLE /* a2 = which CPs are enabled */ + beqz a2, .Ldone /* quick exit if none */ + mov a14, a0 /* save return address */ + call0 XT_RTOS_CP_STATE /* get address of CP save area */ + mov a0, a14 /* restore return address */ + beqz a15, .Ldone /* if none then nothing to do */ + s16i a2, a15, XT_CP_CS_ST /* save mask of CPs being stored */ + movi a13, _xt_coproc_sa_offset /* array of CP save offsets */ + l32i a15, a15, XT_CP_ASA /* a15 = base of aligned save area */ + +#if XCHAL_CP0_SA_SIZE + bbci.l a2, 0, 2f /* CP 0 not enabled */ + l32i a14, a13, 0 /* a14 = _xt_coproc_sa_offset[0] */ + add a3, a14, a15 /* a3 = save area for CP 0 */ + xchal_cp0_store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL +2: +#endif + +#if XCHAL_CP1_SA_SIZE + bbci.l a2, 1, 2f /* CP 1 not enabled */ + l32i a14, a13, 4 /* a14 = _xt_coproc_sa_offset[1] */ + add a3, a14, a15 /* a3 = save area for CP 1 */ + xchal_cp1_store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL +2: +#endif + +#if XCHAL_CP2_SA_SIZE + bbci.l a2, 2, 2f + l32i a14, a13, 8 + add a3, a14, a15 + xchal_cp2_store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL +2: +#endif + +#if XCHAL_CP3_SA_SIZE + bbci.l a2, 3, 2f + l32i a14, a13, 12 + add a3, a14, a15 + xchal_cp3_store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL +2: +#endif + +#if XCHAL_CP4_SA_SIZE + bbci.l a2, 4, 2f + l32i a14, a13, 16 + add a3, a14, a15 + xchal_cp4_store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL +2: +#endif + +#if XCHAL_CP5_SA_SIZE + bbci.l a2, 5, 2f + l32i a14, a13, 20 + add a3, a14, a15 + xchal_cp5_store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL +2: +#endif + +#if XCHAL_CP6_SA_SIZE + bbci.l a2, 6, 2f + l32i a14, a13, 24 + add a3, a14, a15 + xchal_cp6_store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL +2: +#endif + +#if XCHAL_CP7_SA_SIZE + bbci.l a2, 7, 2f + l32i a14, a13, 28 + add a3, a14, a15 + xchal_cp7_store a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL +2: +#endif + +.Ldone: + ret +#endif + + +/******************************************************************************* +_xt_coproc_restorecs + +Restore any callee-saved coprocessor state for the incoming thread. +This function is called from coprocessor exception handling, when giving +ownership to a thread that solicited a context switch earlier. It calls a +system-specific function to get the coprocessor save area base address. + +Entry conditions: + - The incoming thread is set as the current thread. + - CPENABLE is set up correctly for all required coprocessors. + - a2 = mask of coprocessors to be restored. + +Exit conditions: + - All necessary CP callee-saved state has been restored. + - CPENABLE - unchanged. + - Registers a2-a7, a13-a15 have been trashed. + +Must be called from assembly code only, using CALL0. +*******************************************************************************/ +#if XCHAL_CP_NUM > 0 + + .global _xt_coproc_restorecs + .type _xt_coproc_restorecs,@function + .align 4 + .literal_position + .align 4 +_xt_coproc_restorecs: + + mov a14, a0 /* save return address */ + call0 XT_RTOS_CP_STATE /* get address of CP save area */ + mov a0, a14 /* restore return address */ + beqz a15, .Ldone2 /* if none then nothing to do */ + l16ui a3, a15, XT_CP_CS_ST /* a3 = which CPs have been saved */ + xor a3, a3, a2 /* clear the ones being restored */ + s32i a3, a15, XT_CP_CS_ST /* update saved CP mask */ + movi a13, _xt_coproc_sa_offset /* array of CP save offsets */ + l32i a15, a15, XT_CP_ASA /* a15 = base of aligned save area */ + +#if XCHAL_CP0_SA_SIZE + bbci.l a2, 0, 2f /* CP 0 not enabled */ + l32i a14, a13, 0 /* a14 = _xt_coproc_sa_offset[0] */ + add a3, a14, a15 /* a3 = save area for CP 0 */ + xchal_cp0_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL +2: +#endif + +#if XCHAL_CP1_SA_SIZE + bbci.l a2, 1, 2f /* CP 1 not enabled */ + l32i a14, a13, 4 /* a14 = _xt_coproc_sa_offset[1] */ + add a3, a14, a15 /* a3 = save area for CP 1 */ + xchal_cp1_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL +2: +#endif + +#if XCHAL_CP2_SA_SIZE + bbci.l a2, 2, 2f + l32i a14, a13, 8 + add a3, a14, a15 + xchal_cp2_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL +2: +#endif + +#if XCHAL_CP3_SA_SIZE + bbci.l a2, 3, 2f + l32i a14, a13, 12 + add a3, a14, a15 + xchal_cp3_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL +2: +#endif + +#if XCHAL_CP4_SA_SIZE + bbci.l a2, 4, 2f + l32i a14, a13, 16 + add a3, a14, a15 + xchal_cp4_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL +2: +#endif + +#if XCHAL_CP5_SA_SIZE + bbci.l a2, 5, 2f + l32i a14, a13, 20 + add a3, a14, a15 + xchal_cp5_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL +2: +#endif + +#if XCHAL_CP6_SA_SIZE + bbci.l a2, 6, 2f + l32i a14, a13, 24 + add a3, a14, a15 + xchal_cp6_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL +2: +#endif + +#if XCHAL_CP7_SA_SIZE + bbci.l a2, 7, 2f + l32i a14, a13, 28 + add a3, a14, a15 + xchal_cp7_load a3, a4, a5, a6, a7 continue=0 ofs=-1 select=XTHAL_SAS_TIE|XTHAL_SAS_NOCC|XTHAL_SAS_CALE alloc=XTHAL_SAS_ALL +2: +#endif + +.Ldone2: + ret + +#endif diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/xtensa_init.c b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/xtensa_init.c new file mode 100644 index 0000000000..ed816032bd --- /dev/null +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/xtensa_init.c @@ -0,0 +1,62 @@ +/* + * 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 INITIALIZATION ROUTINES CODED IN C + * + * This file contains miscellaneous Xtensa RTOS-generic initialization functions + * that are implemented in C. + */ + + +#ifdef XT_BOARD +#include "xtensa/xtbsp.h" +#endif + +#include "xtensa_rtos.h" +#include "sdkconfig.h" +#include "esp_private/esp_clk.h" + +#ifdef XT_RTOS_TIMER_INT + +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; +} + +/* Deprecated, to be removed */ +int xt_clock_freq(void) +{ + return esp_clk_cpu_freq(); +} + +#endif /* XT_RTOS_TIMER_INT */ diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/xtensa_loadstore_handler.S b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/xtensa_loadstore_handler.S new file mode 100644 index 0000000000..859a6ae81c --- /dev/null +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/xtensa_loadstore_handler.S @@ -0,0 +1,549 @@ +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * LoadStoreErrorCause: Occurs when trying to access 32 bit addressable memory region as 8 bit or 16 bit + * LoadStoreAlignmentCause: Occurs when trying to access in an unaligned manner + * + * xxxx xxxx = imm8 field + * yyyy = imm4 field + * ssss = s field + * tttt = t field + * + * 16 0 + * ------------------- + * L32I.N yyyy ssss tttt 1000 + * S32I.N yyyy ssss tttt 1001 + * + * 23 0 + * ----------------------------- + * L8UI xxxx xxxx 0000 ssss tttt 0010 <- LoadStoreError + * L16UI xxxx xxxx 0001 ssss tttt 0010 <- LoadStoreError, LoadStoreAlignment + * L16SI xxxx xxxx 1001 ssss tttt 0010 <- LoadStoreError, LoadStoreAlignment + * L32I xxxx xxxx 0010 ssss tttt 0010 <- LoadStoreAlignment + * + * S8I xxxx xxxx 0100 ssss tttt 0010 <- LoadStoreError + * S16I xxxx xxxx 0101 ssss tttt 0010 <- LoadStoreError, LoadStoreAlignment + * S32I xxxx xxxx 0110 ssss tttt 0010 <- LoadStoreAlignment + * + * ******* UNSUPPORTED ******* + * + * L32E 0000 1001 rrrr ssss tttt 0000 + * S32E 0100 1001 rrrr ssss tttt 0000 + * ----------------------------- + */ + +#include "xtensa_rtos.h" +#include "sdkconfig.h" +#include "soc/soc.h" + +#define LOADSTORE_HANDLER_STACK_SZ 8 + .section .bss, "aw" + .balign 16 +LoadStoreHandlerStack: + .rept LOADSTORE_HANDLER_STACK_SZ + .word 0 + .endr + + +/* LoadStoreErrorCause handler: + * + * Completes 8-bit or 16-bit load/store instructions from 32-bit aligned memory region + * Called from UserExceptionVector if EXCCAUSE is LoadStoreErrorCause + */ + + .global LoadStoreErrorHandler + .section .iram1, "ax" + + .literal_position + + .balign 4 +LoadStoreErrorHandler: + .type LoadStoreErrorHandler, @function + + wsr a0, depc // Save return address in depc + mov a0, sp + movi sp, LoadStoreHandlerStack + s32i a0, sp, 0x04 // Since a0 contains value of a1 + s32i a2, sp, 0x08 + s32i a3, sp, 0x0c + s32i a4, sp, 0x10 + + rsr a0, sar // Save SAR in a0 to restore later + + /* Check whether the address lies in the valid range */ + rsr a3, excvaddr + movi a4, _iram_text_end // End of code section of IRAM + bge a3, a4, 1f + movi a4, SOC_CACHE_APP_LOW // Check if in APP cache region + blt a3, a4, .LS_wrong_opcode + movi a4, SOC_CACHE_APP_HIGH + bge a3, a4, .LS_wrong_opcode + j 2f + +1: + movi a4, SOC_IRAM_HIGH // End of IRAM address range + bge a3, a4, .LS_wrong_opcode + +2: + /* Examine the opcode which generated the exception */ + /* Note: Instructions are in this order to avoid pipeline stalls. */ + rsr a2, epc1 + movi a4, ~3 + ssa8l a2 // sar is now correct shift for aligned read + and a2, a2, a4 // a2 now 4-byte aligned address of instruction + l32i a4, a2, 0 + l32i a2, a2, 4 + + src a2, a2, a4 // a2 now instruction that failed + bbci a2, 1, .LS_wrong_opcode + bbsi a2, 14, .LSE_store_op // Store instruction + + /* l8/l16ui/l16si */ + movi a4, ~3 + and a4, a3, a4 // a4 now word aligned read address + + ssa8l a3 // sar is now shift to extract a3's byte + l32i a4, a4, 0 // perform the actual read + srl a4, a4 // shift right correct distance + extui a3, a2, 12, 4 + bnez a3, 1f // l16ui/l16si + extui a4, a4, 0, 8 // mask off bits needed for an l8 + j 2f + +1: + extui a4, a4, 0, 16 + bbci a2, 15, 2f // l16ui + + /* Sign adjustment */ + slli a4, a4, 16 + srai a4, a4, 16 // a4 contains the value + +2: + /* a4 contains the value */ + rsr a3, epc1 + addi a3, a3, 3 + wsr a3, epc1 + wsr a0, sar + rsr a0, excsave1 + + extui a2, a2, 3, 5 + blti a2, 10, .LSE_stack_reg + + movi a3, .LS_jumptable_base + addx8 a2, a2, a3 // a2 is now the address to jump to + l32i a3, sp, 0x0c + jx a2 + +.LSE_stack_reg: + addx2 a2, a2, sp + s32i a4, a2, 0 + + /* Restore all values */ + l32i a4, sp, 0x10 + l32i a3, sp, 0x0c + l32i a2, sp, 0x08 + l32i a1, sp, 0x04 + rfe + +.LSE_store_op: + s32i a5, a1, 0x14 + s32i a6, a1, 0x18 + + /* a2 -> instruction that caused the error */ + /* a3 -> unaligned address */ + extui a4, a2, 4, 4 + blti a4, 7, 1f + movi a5, .LSE_store_reg + addx8 a5, a4, a5 + jx a5 + +1: + addx4 a4, a4, sp + l32i a4, a4, 0 + +.LSE_store_data: + /* a4 contains the value */ + rsr a6, epc1 + addi a6, a6, 3 + wsr a6, epc1 + + ssa8b a3 + movi a5, -1 + bbsi a2, 12, 1f // s16 + extui a4, a4, 0, 8 + movi a6, 0xff + j 2f +1: + extui a4, a4, 0, 16 + movi a6, 0xffff +2: + sll a4, a4 // shift the value to proper offset + sll a6, a6 + xor a5, a5, a6 // a5 contains the mask + + movi a6, ~3 + and a3, a3, a6 // a3 has the aligned address + l32i a6, a3, 0 // a6 contains the data at the aligned address + and a6, a6, a5 + or a4, a6, a4 + s32i a4, a3, 0 + + /* Restore registers */ + wsr a0, sar + + l32i a6, sp, 0x18 + l32i a5, sp, 0x14 + l32i a4, sp, 0x10 + l32i a3, sp, 0x0c + l32i a2, sp, 0x08 + l32i a1, sp, 0x04 + rsr a0, excsave1 + + rfe + +.LSE_store_reg: + .org .LSE_store_reg + (7 * 8) + mov a4, a7 + j .LSE_store_data + + .org .LSE_store_reg + (8 * 8) + mov a4, a8 + j .LSE_store_data + + .org .LSE_store_reg + (9 * 8) + mov a4, a9 + j .LSE_store_data + + .org .LSE_store_reg + (10 * 8) + mov a4, a10 + j .LSE_store_data + + .org .LSE_store_reg + (11 * 8) + mov a4, a11 + j .LSE_store_data + + .org .LSE_store_reg + (12 * 8) + mov a4, a12 + j .LSE_store_data + + .org .LSE_store_reg + (13 * 8) + mov a4, a13 + j .LSE_store_data + + .org .LSE_store_reg + (14 * 8) + mov a4, a14 + j .LSE_store_data + + .org .LSE_store_reg + (15 * 8) + mov a4, a15 + j .LSE_store_data + + +/* LoadStoreAlignmentCause handler: + * + * Completes unaligned 16-bit and 32-bit load/store instructions from 32-bit aligned memory region + * Called from UserExceptionVector if EXCCAUSE is LoadStoreAlignmentCause + */ + + .global AlignmentErrorHandler + .section .iram1, "ax" + + .literal_position + + .balign 4 +AlignmentErrorHandler: + .type AlignmentErrorHandler, @function + + wsr a0, depc // Save return address in depc + mov a0, sp + movi sp, LoadStoreHandlerStack + s32i a0, sp, 0x04 // Since a0 contains value of a1 + s32i a2, sp, 0x08 + s32i a3, sp, 0x0c + s32i a4, sp, 0x10 + + rsr a0, sar // Save SAR in a0 to restore later + + /* Check whether the address lies in the valid range */ + rsr a3, excvaddr + movi a4, _iram_text_end // End of code section of IRAM + bge a3, a4, 1f + movi a4, SOC_CACHE_APP_LOW // Check if in APP cache region + blt a3, a4, .LS_wrong_opcode + movi a4, SOC_CACHE_APP_HIGH + bge a3, a4, .LS_wrong_opcode + j 2f + +1: + movi a4, SOC_IRAM_HIGH // End of IRAM address range + bge a3, a4, .LS_wrong_opcode + +2: + /* Examine the opcode which generated the exception */ + /* Note: Instructions are in this order to avoid pipeline stalls. */ + rsr a2, epc1 + movi a4, ~3 + ssa8l a2 // sar is now correct shift for aligned read + and a2, a2, a4 // a2 now 4-byte aligned address of instruction + l32i a4, a2, 0 + l32i a2, a2, 4 + + /* a2 has the instruction that caused the error */ + src a2, a2, a4 + extui a4, a2, 0, 4 + addi a4, a4, -9 + beqz a4, .LSA_store_op + bbsi a2, 14, .LSA_store_op + + ssa8l a3 // a3 contains the unaligned address + movi a4, ~3 + and a4, a3, a4 // a4 has the aligned address + l32i a3, a4, 0 + l32i a4, a4, 4 + src a4, a4, a3 + + rsr a3, epc1 + addi a3, a3, 2 + bbsi a2, 3, 1f // l32i.n + bbci a2, 1, .LS_wrong_opcode + addi a3, a3, 1 + + bbsi a2, 13, 1f // l32 + extui a4, a4, 0, 16 + bbci a2, 15, 1f // l16ui + + /* Sign adjustment */ + slli a4, a4, 16 + srai a4, a4, 16 // a4 contains the value + +1: + wsr a3, epc1 + wsr a0, sar + rsr a0, excsave1 + + extui a2, a2, 4, 4 + blti a2, 5, .LSA_stack_reg // a3 contains the target register + + movi a3, .LS_jumptable_base + slli a2, a2, 4 + add a2, a2, a3 // a2 is now the address to jump to + l32i a3, sp, 0x0c + jx a2 + +.LSA_stack_reg: + addx4 a2, a2, sp + s32i a4, a2, 0 + + /* Restore all values */ + l32i a4, sp, 0x10 + l32i a3, sp, 0x0c + l32i a2, sp, 0x08 + l32i a1, sp, 0x04 + rfe + +/* Store instruction */ +.LSA_store_op: + s32i a5, sp, 0x14 + s32i a6, sp, 0x18 + s32i a7, sp, 0x1c + + /* a2 -> instruction that caused the error */ + /* a3 -> unaligned address */ + extui a4, a2, 4, 4 + blti a4, 8, 1f + movi a5, .LSA_store_reg + addx8 a5, a4, a5 + jx a5 + +1: + addx4 a4, a4, sp + l32i a4, a4, 0 // a4 contains the value + +.LSA_store_data: + movi a6, 0 + + rsr a7, epc1 + addi a7, a7 ,2 + bbsi a2, 3, 1f // s32i.n + bbci a2, 1, .LS_wrong_opcode + + addi a7, a7, 1 + bbsi a2, 13, 1f // s32i + + movi a5, -1 + extui a4, a4, 0, 16 + slli a6, a5, 16 // 0xffff0000 + +1: + wsr a7, epc1 + movi a5, ~3 + and a5, a3, a5 // a5 has the aligned address + + ssa8b a3 + movi a3, -1 + src a7, a6, a3 + src a3, a3, a6 + + /* Store data on lower address */ + l32i a6, a5, 0 + and a6, a6, a7 + sll a7, a4 + or a6, a6, a7 + s32i a6, a5, 0 + + /* Store data on higher address */ + l32i a7, a5, 4 + srl a6, a4 + and a3, a7, a3 + or a3, a3, a6 + s32i a3, a5, 4 + + /* Restore registers */ + wsr a0, sar + rsr a0, excsave1 + + l32i a7, sp, 0x1c + l32i a6, sp, 0x18 + l32i a5, sp, 0x14 + l32i a4, sp, 0x10 + l32i a3, sp, 0x0c + l32i a2, sp, 0x08 + l32i a1, sp, 0x04 + rfe + +.LSA_store_reg: + .org .LSA_store_reg + (8 * 8) + mov a4, a8 + j .LSA_store_data + + .org .LSA_store_reg + (9 * 8) + mov a4, a9 + j .LSA_store_data + + .org .LSA_store_reg + (10 * 8) + mov a4, a10 + j .LSA_store_data + + .org .LSA_store_reg + (11 * 8) + mov a4, a11 + j .LSA_store_data + + .org .LSA_store_reg + (12 * 8) + mov a4, a12 + j .LSA_store_data + + .org .LSA_store_reg + (13 * 8) + mov a4, a13 + j .LSA_store_data + + .org .LSA_store_reg + (14 * 8) + mov a4, a14 + j .LSA_store_data + + .org .LSA_store_reg + (15 * 8) + mov a4, a15 + j .LSA_store_data + +/* + * Common routines for both the exception handlers + */ + .balign 4 +.LS_jumptable: + /* The first 5 entries (80 bytes) of this table are unused (registers + a0..a4 are handled separately above). Rather than have a whole bunch + of wasted space, just pretend that the table starts 80 bytes + earlier in memory. */ + .set .LS_jumptable_base, .LS_jumptable - (16 * 5) + + .org .LS_jumptable_base + (16 * 5) + mov a5, a4 + l32i a4, sp, 0x10 + l32i a2, sp, 0x08 + l32i a1, sp, 0x04 + rfe + + .org .LS_jumptable_base + (16 * 6) + mov a6, a4 + l32i a4, sp, 0x10 + l32i a2, sp, 0x08 + l32i a1, sp, 0x04 + rfe + + .org .LS_jumptable_base + (16 * 7) + mov a7, a4 + l32i a4, sp, 0x10 + l32i a2, sp, 0x08 + l32i a1, sp, 0x04 + rfe + + .org .LS_jumptable_base + (16 * 8) + mov a8, a4 + l32i a4, sp, 0x10 + l32i a2, sp, 0x08 + l32i a1, sp, 0x04 + rfe + + .org .LS_jumptable_base + (16 * 9) + mov a9, a4 + l32i a4, sp, 0x10 + l32i a2, sp, 0x08 + l32i a1, sp, 0x04 + rfe + + .org .LS_jumptable_base + (16 * 10) + mov a10, a4 + l32i a4, sp, 0x10 + l32i a2, sp, 0x08 + l32i a1, sp, 0x04 + rfe + + .org .LS_jumptable_base + (16 * 11) + mov a11, a4 + l32i a4, sp, 0x10 + l32i a2, sp, 0x08 + l32i a1, sp, 0x04 + rfe + + .org .LS_jumptable_base + (16 * 12) + mov a12, a4 + l32i a4, sp, 0x10 + l32i a2, sp, 0x08 + l32i a1, sp, 0x04 + rfe + + .org .LS_jumptable_base + (16 * 13) + mov a13, a4 + l32i a4, sp, 0x10 + l32i a2, sp, 0x08 + l32i a1, sp, 0x04 + rfe + + .org .LS_jumptable_base + (16 * 14) + mov a14, a4 + l32i a4, sp, 0x10 + l32i a2, sp, 0x08 + l32i a1, sp, 0x04 + rfe + + .org .LS_jumptable_base + (16 * 15) + mov a15, a4 + l32i a4, sp, 0x10 + l32i a2, sp, 0x08 + l32i a1, sp, 0x04 + rfe + +.LS_wrong_opcode: + /* Reaches here if the address is in invalid range or the opcode isn't supported. + * Restore registers and jump back to _xt_user_exc + */ + wsr a0, sar + l32i a4, sp, 0x10 + l32i a3, sp, 0x0c + l32i a2, sp, 0x08 + l32i a1, sp, 0x04 + rsr a0, depc + ret // Equivalent to jx a0 diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/xtensa_overlay_os_hook.c b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/xtensa_overlay_os_hook.c new file mode 100644 index 0000000000..38258f3b7c --- /dev/null +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/xtensa_overlay_os_hook.c @@ -0,0 +1,77 @@ +/* + * 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_overlay_os_hook.c -- Overlay manager OS hooks for FreeRTOS. + */ + +#include "FreeRTOS.h" +#include "semphr.h" + +#if configUSE_MUTEXES + +/* Mutex object that controls access to the overlay. Currently only one + * overlay region is supported so one mutex suffices. + */ +static SemaphoreHandle_t xt_overlay_mutex; + + +/* This function should be overridden to provide OS specific init such + * as the creation of a mutex lock that can be used for overlay locking. + * Typically this mutex would be set up with priority inheritance. See + * overlay manager documentation for more details. + */ +void xt_overlay_init_os(void) +{ + /* Create the mutex for overlay access. Priority inheritance is + * required. + */ + xt_overlay_mutex = xSemaphoreCreateMutex(); +} + + +/* This function locks access to shared overlay resources, typically + * by acquiring a mutex. + */ +void xt_overlay_lock(void) +{ + xSemaphoreTake(xt_overlay_mutex, 0); +} + + +/* This function releases access to shared overlay resources, typically + * by unlocking a mutex. + */ +void xt_overlay_unlock(void) +{ + xSemaphoreGive(xt_overlay_mutex); +} + +#endif diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/xtensa_vector_defaults.S b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/xtensa_vector_defaults.S new file mode 100644 index 0000000000..628b75aef5 --- /dev/null +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/xtensa_vector_defaults.S @@ -0,0 +1,230 @@ +/* + * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "xtensa_rtos.h" +#include "esp_private/panic_reason.h" +#include "sdkconfig.h" +#include "soc/soc.h" + +/* +This file contains the default handlers for the high interrupt levels as well as some specialized exceptions. +The default behaviour is to just exit the interrupt or call the panic handler on the exceptions +*/ + + +#if XCHAL_HAVE_DEBUG + .global xt_debugexception + .weak xt_debugexception + .set xt_debugexception, _xt_debugexception + .section .iram1,"ax" + .type _xt_debugexception,@function + .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 + crashing anyhow, copy EPC & EXCSAVE from DEBUGLEVEL + to level 1. */ + rsr a0,(EPC + XCHAL_DEBUGLEVEL) + wsr a0,EPC_1 + rsr a0,(EXCSAVE + XCHAL_DEBUGLEVEL) + wsr a0,EXCSAVE_1 + 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 */ + + +#if XCHAL_NUM_INTLEVELS >=2 && XCHAL_EXCM_LEVEL <2 && XCHAL_DEBUGLEVEL !=2 + .global xt_highint2 + .weak xt_highint2 + .set xt_highint2, _xt_highint2 + .section .iram1,"ax" + .type _xt_highint2,@function + .align 4 +_xt_highint2: + + /* Default handler does nothing; just returns */ + .align 4 +.L_xt_highint2_exit: + rsr a0, EXCSAVE_2 /* restore a0 */ + rfi 2 + +#endif /* Level 2 */ + +#if XCHAL_NUM_INTLEVELS >=3 && XCHAL_EXCM_LEVEL <3 && XCHAL_DEBUGLEVEL !=3 + + .global xt_highint3 + .weak xt_highint3 + .set xt_highint3, _xt_highint3 + .section .iram1,"ax" + .type _xt_highint3,@function + .align 4 +_xt_highint3: + + /* Default handler does nothing; just returns */ + + .align 4 +.L_xt_highint3_exit: + rsr a0, EXCSAVE_3 /* restore a0 */ + rfi 3 + +#endif /* Level 3 */ + +#if XCHAL_NUM_INTLEVELS >=4 && XCHAL_EXCM_LEVEL <4 && XCHAL_DEBUGLEVEL !=4 + + .global xt_highint4 + .weak xt_highint4 + .set xt_highint4, _xt_highint4 + .section .iram1,"ax" + .type _xt_highint4,@function + .align 4 +_xt_highint4: + + /* Default handler does nothing; just returns */ + + .align 4 +.L_xt_highint4_exit: + rsr a0, EXCSAVE_4 /* restore a0 */ + rfi 4 + +#endif /* Level 4 */ + +#if XCHAL_NUM_INTLEVELS >=5 && XCHAL_EXCM_LEVEL <5 && XCHAL_DEBUGLEVEL !=5 + + .global xt_highint5 + .weak xt_highint5 + .set xt_highint5, _xt_highint5 + .section .iram1,"ax" + .type _xt_highint5,@function + .align 4 +_xt_highint5: + + /* Default handler does nothing; just returns */ + + .align 4 +.L_xt_highint5_exit: + rsr a0, EXCSAVE_5 /* restore a0 */ + rfi 5 + + +#endif /* Level 5 */ + +#if XCHAL_NUM_INTLEVELS >=6 && XCHAL_EXCM_LEVEL <6 && XCHAL_DEBUGLEVEL !=6 + + .global _xt_highint6 + .global xt_highint6 + .weak xt_highint6 + .set xt_highint6, _xt_highint6 + .section .iram1,"ax" + .type _xt_highint6,@function + .align 4 +_xt_highint6: + + /* Default handler does nothing; just returns */ + + .align 4 +.L_xt_highint6_exit: + rsr a0, EXCSAVE_6 /* restore a0 */ + rfi 6 + +#endif /* Level 6 */ + +#if XCHAL_HAVE_NMI + + .global _xt_nmi + .global xt_nmi + .weak xt_nmi + .set xt_nmi, _xt_nmi + .section .iram1,"ax" + .type _xt_nmi,@function + .align 4 +_xt_nmi: + + /* Default handler does nothing; just returns */ + + .align 4 +.L_xt_nmi_exit: + rsr a0, EXCSAVE + XCHAL_NMILEVEL /* restore a0 */ + rfi XCHAL_NMILEVEL + +#endif /* NMI */ diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/xtensa_vectors.S b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/xtensa_vectors.S new file mode 100644 index 0000000000..e70de48ba0 --- /dev/null +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/xtensa_vectors.S @@ -0,0 +1,1945 @@ +/* + * 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 VECTORS AND LOW LEVEL HANDLERS FOR AN RTOS + + Xtensa low level exception and interrupt vectors and handlers for an RTOS. + + Interrupt handlers and user exception handlers support interaction with + the RTOS by calling XT_RTOS_INT_ENTER and XT_RTOS_INT_EXIT before and + after user's specific interrupt handlers. These macros are defined in + xtensa_.h to call suitable functions in a specific RTOS. + + Users can install application-specific interrupt handlers for low and + medium level interrupts, by calling xt_set_interrupt_handler(). These + handlers can be written in C, and must obey C calling convention. The + handler table is indexed by the interrupt number. Each handler may be + provided with an argument. + + Note that the system timer interrupt is handled specially, and is + dispatched to the RTOS-specific handler. This timer cannot be hooked + by application code. + + Optional hooks are also provided to install a handler per level at + run-time, made available by compiling this source file with + '-DXT_INTEXC_HOOKS' (useful for automated testing). + +!! This file is a template that usually needs to be modified to handle !! +!! application specific interrupts. Search USER_EDIT for helpful comments !! +!! on where to insert handlers and how to write them. !! + + Users can also install application-specific exception handlers in the + same way, by calling xt_set_exception_handler(). One handler slot is + provided for each exception type. Note that some exceptions are handled + by the porting layer itself, and cannot be taken over by application + code in this manner. These are the alloca, syscall, and coprocessor + exceptions. + + The exception handlers can be written in C, and must follow C calling + convention. Each handler is passed a pointer to an exception frame as + its single argument. The exception frame is created on the stack, and + holds the saved context of the thread that took the exception. If the + handler returns, the context will be restored and the instruction that + caused the exception will be retried. If the handler makes any changes + to the saved state in the exception frame, the changes will be applied + when restoring the context. + + Because Xtensa is a configurable architecture, this port supports all user + generated configurations (except restrictions stated in the release notes). + This is accomplished by conditional compilation using macros and functions + defined in the Xtensa HAL (hardware adaptation layer) for your configuration. + Only the relevant parts of this file will be included in your RTOS build. + For example, this file provides interrupt vector templates for all types and + all priority levels, but only the ones in your configuration are built. + + NOTES on the use of 'call0' for long jumps instead of 'j': + 1. This file should be assembled with the -mlongcalls option to xt-xcc. + 2. The -mlongcalls compiler option causes 'call0 dest' to be expanded to + a sequence 'l32r a0, dest' 'callx0 a0' which works regardless of the + distance from the call to the destination. The linker then relaxes + it back to 'call0 dest' if it determines that dest is within range. + This allows more flexibility in locating code without the performance + overhead of the 'l32r' literal data load in cases where the destination + is in range of 'call0'. There is an additional benefit in that 'call0' + has a longer range than 'j' due to the target being word-aligned, so + the 'l32r' sequence is less likely needed. + 3. The use of 'call0' with -mlongcalls requires that register a0 not be + live at the time of the call, which is always the case for a function + call but needs to be ensured if 'call0' is used as a jump in lieu of 'j'. + 4. This use of 'call0' is independent of the C function call ABI. + + */ + +#include "xtensa_rtos.h" +#include "esp_private/panic_reason.h" +#include "sdkconfig.h" +#include "soc/soc.h" + +/* + Define for workaround: pin no-cpu-affinity tasks to a cpu when fpu is used. + Please change this when the tcb structure is changed +*/ +#define TASKTCB_XCOREID_OFFSET (0x38+configMAX_TASK_NAME_LEN+3)&~3 +.extern pxCurrentTCB + +/* +-------------------------------------------------------------------------------- + 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 + + +/* +-------------------------------------------------------------------------------- + Defines used to access _xtos_interrupt_table. +-------------------------------------------------------------------------------- +*/ +#define XIE_HANDLER 0 +#define XIE_ARG 4 +#define XIE_SIZE 8 + + +/* + Macro get_percpu_entry_for - convert a per-core ID into a multicore entry. + Basically does reg=reg*portNUM_PROCESSORS+current_core_id + Multiple versions here to optimize for specific portNUM_PROCESSORS values. +*/ + .macro get_percpu_entry_for reg scratch +#if (portNUM_PROCESSORS == 1) + /* No need to do anything */ +#elif (portNUM_PROCESSORS == 2) + /* Optimized 2-core code. */ + getcoreid \scratch + addx2 \reg,\reg,\scratch +#else + /* Generalized n-core code. Untested! */ + movi \scratch,portNUM_PROCESSORS + mull \scratch,\reg,\scratch + getcoreid \reg + add \reg,\scratch,\reg +#endif + .endm +/* +-------------------------------------------------------------------------------- + Macro extract_msb - return the input with only the highest bit set. + + Input : "ain" - Input value, clobbered. + Output : "aout" - Output value, has only one bit set, MSB of "ain". + The two arguments must be different AR registers. +-------------------------------------------------------------------------------- +*/ + + .macro extract_msb aout ain +1: + addi \aout, \ain, -1 /* aout = ain - 1 */ + and \ain, \ain, \aout /* ain = ain & aout */ + bnez \ain, 1b /* repeat until ain == 0 */ + addi \aout, \aout, 1 /* return aout + 1 */ + .endm + +/* +-------------------------------------------------------------------------------- + Macro dispatch_c_isr - dispatch interrupts to user ISRs. + This will dispatch to user handlers (if any) that are registered in the + XTOS dispatch table (_xtos_interrupt_table). These handlers would have + been registered by calling _xtos_set_interrupt_handler(). There is one + exception - the timer interrupt used by the OS will not be dispatched + to a user handler - this must be handled by the caller of this macro. + + Level triggered and software interrupts are automatically deasserted by + this code. + + ASSUMPTIONS: + -- PS.INTLEVEL is set to "level" at entry + -- PS.EXCM = 0, C calling enabled + + NOTE: For CALL0 ABI, a12-a15 have not yet been saved. + + NOTE: This macro will use registers a0 and a2-a6. The arguments are: + level -- interrupt level + mask -- interrupt bitmask for this level +-------------------------------------------------------------------------------- +*/ + + .macro dispatch_c_isr level mask + + #ifdef CONFIG_PM_TRACE + movi a6, 0 /* = ESP_PM_TRACE_IDLE */ + getcoreid a7 + call4 esp_pm_trace_exit + #endif // CONFIG_PM_TRACE + + /* Get mask of pending, enabled interrupts at this level into a2. */ + +.L_xt_user_int_&level&: + rsr a2, INTENABLE + rsr a3, INTERRUPT + movi a4, \mask + and a2, a2, a3 + and a2, a2, a4 + beqz a2, 9f /* nothing to do */ + + /* 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__ + 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 + /* 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 */ + addx2 a0, a4, a0 /* clear top bit -- simulating call4 size */ + #endif + #endif + + #ifdef CONFIG_PM_ENABLE + call4 esp_pm_impl_isr_hook + #endif + + #ifdef XT_INTEXC_HOOKS + /* Call interrupt hook if present to (pre)handle interrupts. */ + movi a4, _xt_intexc_hooks + l32i a4, a4, \level << 2 + beqz a4, 2f + #ifdef __XTENSA_CALL0_ABI__ + callx0 a4 + beqz a2, 9f + #else + mov a6, a2 + callx4 a4 + beqz a6, 9f + mov a2, a6 + #endif +2: + #endif + + /* Now look up in the dispatch table and call user ISR if any. */ + /* If multiple bits are set then MSB has highest priority. */ + + extract_msb a4, a2 /* a4 = MSB of a2, a2 trashed */ + + #ifdef XT_USE_SWPRI + /* Enable all interrupts at this level that are numerically higher + than the one we just selected, since they are treated as higher + priority. + */ + movi a3, \mask /* a3 = all interrupts at this level */ + add a2, a4, a4 /* a2 = a4 << 1 */ + addi a2, a2, -1 /* a2 = mask of 1's <= a4 bit */ + and a2, a2, a3 /* a2 = mask of all bits <= a4 at this level */ + movi a3, _xt_intdata + l32i a6, a3, 4 /* a6 = _xt_vpri_mask */ + neg a2, a2 + addi a2, a2, -1 /* a2 = mask to apply */ + and a5, a6, a2 /* mask off all bits <= a4 bit */ + s32i a5, a3, 4 /* update _xt_vpri_mask */ + rsr a3, INTENABLE + and a3, a3, a2 /* mask off all bits <= a4 bit */ + wsr a3, INTENABLE + 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 */ + + get_percpu_entry_for a3, a12 + movi a4, _xt_interrupt_table + addx8 a3, a3, a4 /* a3 = address of interrupt table entry */ + l32i a4, a3, XIE_HANDLER /* a4 = handler address */ + #ifdef __XTENSA_CALL0_ABI__ + mov a12, a6 /* save in callee-saved reg */ + l32i a2, a3, XIE_ARG /* a2 = handler arg */ + callx0 a4 /* call handler */ + mov a2, a12 + #else + mov a2, a6 /* save in windowed reg */ + l32i a6, a3, XIE_ARG /* a6 = handler arg */ + callx4 a4 /* call handler */ + #endif + + #ifdef XT_USE_SWPRI + j 8f + #else + j .L_xt_user_int_&level& /* check for more interrupts */ + #endif + + #ifdef XT_RTOS_TIMER_INT +7: + + .ifeq XT_TIMER_INTPRI - \level +.L_xt_user_int_timer_&level&: + /* + Interrupt handler for the RTOS tick timer if at this level. + We'll be reading the interrupt state again after this call + so no need to preserve any registers except a6 (vpri_mask). + */ + + #ifdef __XTENSA_CALL0_ABI__ + mov a12, a6 + call0 XT_RTOS_TIMER_INT + mov a2, a12 + #else + mov a2, a6 + call4 XT_RTOS_TIMER_INT + #endif + .endif + #endif // XT_RTOS_TIMER_INT + + #ifdef XT_USE_SWPRI + j 8f + #else + j .L_xt_user_int_&level& /* check for more interrupts */ + #endif + + #ifdef XT_USE_SWPRI +8: + /* Restore old value of _xt_vpri_mask from a2. Also update INTENABLE from + virtual _xt_intenable which _could_ have changed during interrupt + processing. */ + + movi a3, _xt_intdata + l32i a4, a3, 0 /* a4 = _xt_intenable */ + s32i a2, a3, 4 /* update _xt_vpri_mask */ + and a4, a4, a2 /* a4 = masked intenable */ + wsr a4, INTENABLE /* update INTENABLE */ + #endif + +9: + /* done */ + + .endm + + + .section .rodata, "a" + .align 4 + +/* +-------------------------------------------------------------------------------- + Hooks to dynamically install handlers for exceptions and interrupts. + Allows automated regression frameworks to install handlers per test. + Consists of an array of function pointers indexed by interrupt level, + with index 0 containing the entry for user exceptions. + Initialized with all 0s, meaning no handler is installed at each level. + See comment in xtensa_rtos.h for more details. + + *WARNING* This array is for all CPUs, that is, installing a hook for + one CPU will install it for all others as well! +-------------------------------------------------------------------------------- +*/ + + #ifdef XT_INTEXC_HOOKS + .data + .global _xt_intexc_hooks + .type _xt_intexc_hooks,@object + .align 4 + +_xt_intexc_hooks: + .fill XT_INTEXC_HOOK_NUM, 4, 0 + #endif + + +/* +-------------------------------------------------------------------------------- + EXCEPTION AND LEVEL 1 INTERRUPT VECTORS AND LOW LEVEL HANDLERS + (except window exception vectors). + + Each vector goes at a predetermined location according to the Xtensa + hardware configuration, which is ensured by its placement in a special + section known to the Xtensa linker support package (LSP). It performs + the minimum necessary before jumping to the handler in the .text section. + + The corresponding handler goes in the normal .text section. It sets up + the appropriate stack frame, saves a few vector-specific registers and + calls XT_RTOS_INT_ENTER to save the rest of the interrupted context + and enter the RTOS, then sets up a C environment. It then calls the + user's interrupt handler code (which may be coded in C) and finally + calls XT_RTOS_INT_EXIT to transfer control to the RTOS for scheduling. + + While XT_RTOS_INT_EXIT does not return directly to the interruptee, + eventually the RTOS scheduler will want to dispatch the interrupted + task or handler. The scheduler will return to the exit point that was + saved in the interrupt stack frame at XT_STK_EXIT. +-------------------------------------------------------------------------------- +*/ + + +/* +-------------------------------------------------------------------------------- +Debug Exception. +-------------------------------------------------------------------------------- +*/ + +#if XCHAL_HAVE_DEBUG + + .begin literal_prefix .DebugExceptionVector + .section .DebugExceptionVector.text, "ax" + .global _DebugExceptionVector + .align 4 + .global xt_debugexception +_DebugExceptionVector: + wsr a0, EXCSAVE+XCHAL_DEBUGLEVEL /* preserve a0 */ + call0 xt_debugexception /* load exception handler */ + + .end literal_prefix + +#endif + +/* +-------------------------------------------------------------------------------- +Double Exception. +Double exceptions are not a normal occurrence. They indicate a bug of some kind. +-------------------------------------------------------------------------------- +*/ + +#ifdef XCHAL_DOUBLEEXC_VECTOR_VADDR + + .begin literal_prefix .DoubleExceptionVector + .section .DoubleExceptionVector.text, "ax" + .global _DoubleExceptionVector + .align 4 + +_DoubleExceptionVector: + + #if XCHAL_HAVE_DEBUG + break 1, 4 /* unhandled double exception */ + #endif + movi a0,PANIC_RSN_DOUBLEEXCEPTION + wsr a0,EXCCAUSE + call0 _xt_panic /* does not return */ + rfde /* make a0 point here not later */ + + .end literal_prefix + +#endif /* XCHAL_DOUBLEEXC_VECTOR_VADDR */ + +/* +-------------------------------------------------------------------------------- +Kernel Exception (including Level 1 Interrupt from kernel mode). +-------------------------------------------------------------------------------- +*/ + + .begin literal_prefix .KernelExceptionVector + .section .KernelExceptionVector.text, "ax" + .global _KernelExceptionVector + .align 4 + +_KernelExceptionVector: + + wsr a0, EXCSAVE_1 /* preserve a0 */ + call0 _xt_kernel_exc /* kernel exception handler */ + /* never returns here - call0 is used as a jump (see note at top) */ + + .end literal_prefix + + .section .iram1,"ax" + .align 4 + +_xt_kernel_exc: + #if XCHAL_HAVE_DEBUG + break 1, 0 /* unhandled kernel exception */ + #endif + movi a0,PANIC_RSN_KERNELEXCEPTION + wsr a0,EXCCAUSE + call0 _xt_panic /* does not return */ + rfe /* make a0 point here not there */ + + +/* +-------------------------------------------------------------------------------- +User Exception (including Level 1 Interrupt from user mode). +-------------------------------------------------------------------------------- +*/ + + .begin literal_prefix .UserExceptionVector + .section .UserExceptionVector.text, "ax" + .global _UserExceptionVector + .type _UserExceptionVector,@function + .align 4 + +_UserExceptionVector: + + wsr a0, EXCSAVE_1 /* preserve a0 */ + call0 _xt_user_exc /* user exception handler */ + /* never returns here - call0 is used as a jump (see note at top) */ + + .end literal_prefix + +/* +-------------------------------------------------------------------------------- + Insert some waypoints for jumping beyond the signed 8-bit range of + conditional branch instructions, so the conditional branchces to specific + exception handlers are not taken in the mainline. Saves some cycles in the + mainline. +-------------------------------------------------------------------------------- +*/ + +#ifdef CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY + .global LoadStoreErrorHandler + .global AlignmentErrorHandler +#endif + + .section .iram1,"ax" + + #if XCHAL_HAVE_WINDOWED + .align 4 +_xt_to_alloca_exc: + call0 _xt_alloca_exc /* in window vectors section */ + /* never returns here - call0 is used as a jump (see note at top) */ + #endif + + .align 4 +_xt_to_syscall_exc: + call0 _xt_syscall_exc + /* never returns here - call0 is used as a jump (see note at top) */ + + #if XCHAL_CP_NUM > 0 + .align 4 +_xt_to_coproc_exc: + call0 _xt_coproc_exc + /* never returns here - call0 is used as a jump (see note at top) */ + #endif + +#ifdef CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY + .align 4 +_call_loadstore_handler: + call0 LoadStoreErrorHandler + /* This will return only if wrong opcode or address out of range*/ + j .LS_exit + + .align 4 +_call_alignment_handler: + call0 AlignmentErrorHandler + /* This will return only if wrong opcode or address out of range*/ + addi a0, a0, 1 + j .LS_exit +#endif + +/* +-------------------------------------------------------------------------------- + User exception handler. +-------------------------------------------------------------------------------- +*/ + + .type _xt_user_exc,@function + .align 4 + +_xt_user_exc: + + /* If level 1 interrupt then jump to the dispatcher */ + rsr a0, EXCCAUSE + beqi a0, EXCCAUSE_LEVEL1INTERRUPT, _xt_lowint1 + + /* Handle any coprocessor exceptions. Rely on the fact that exception + numbers above EXCCAUSE_CP0_DISABLED all relate to the coprocessors. + */ + #if XCHAL_CP_NUM > 0 + bgeui a0, EXCCAUSE_CP0_DISABLED, _xt_to_coproc_exc + #endif + + /* Handle alloca and syscall exceptions */ + #if XCHAL_HAVE_WINDOWED + beqi a0, EXCCAUSE_ALLOCA, _xt_to_alloca_exc + #endif + beqi a0, EXCCAUSE_SYSCALL, _xt_to_syscall_exc + +#ifdef CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY + beqi a0, EXCCAUSE_LOAD_STORE_ERROR, _call_loadstore_handler + + addi a0, a0, -1 + beqi a0, 8, _call_alignment_handler + addi a0, a0, 1 +.LS_exit: +#endif + + /* Handle all other exceptions. All can have user-defined handlers. */ + /* NOTE: we'll stay on the user stack for exception handling. */ + + /* Allocate exception frame and save minimal context. */ + mov a0, sp + addi sp, sp, -XT_STK_FRMSZ + s32i a0, sp, XT_STK_A1 + #if XCHAL_HAVE_WINDOWED + s32e a0, sp, -12 /* for debug backtrace */ + #endif + rsr a0, PS /* save interruptee's PS */ + s32i a0, sp, XT_STK_PS + rsr a0, EPC_1 /* save interruptee's PC */ + s32i a0, sp, XT_STK_PC + rsr a0, EXCSAVE_1 /* save interruptee's a0 */ + s32i a0, sp, XT_STK_A0 + #if XCHAL_HAVE_WINDOWED + s32e a0, sp, -16 /* for debug backtrace */ + #endif + s32i a12, sp, XT_STK_A12 /* _xt_context_save requires A12- */ + s32i a13, sp, XT_STK_A13 /* A13 to have already been saved */ + call0 _xt_context_save + + /* Save exc cause and vaddr into exception frame */ + rsr a0, EXCCAUSE + s32i a0, sp, XT_STK_EXCCAUSE + rsr a0, EXCVADDR + s32i a0, sp, XT_STK_EXCVADDR + + /* Set up PS for C, reenable debug and NMI interrupts, and clear EXCM. */ + #ifdef __XTENSA_CALL0_ABI__ + movi a0, PS_INTLEVEL(XCHAL_DEBUGLEVEL - 2) | PS_UM + #else + movi a0, PS_INTLEVEL(XCHAL_DEBUGLEVEL - 2) | PS_UM | PS_WOE + #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__ + 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 + 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 */ + or a0, a0, a5 /* set top 2 bits */ + addx2 a0, a5, a0 /* clear top bit -- thus simulating call4 size */ + #else + rsync /* wait for WSR.PS to complete */ + #endif + #endif + + rsr a2, EXCCAUSE /* recover exc cause */ + + #ifdef XT_INTEXC_HOOKS + /* + Call exception hook to pre-handle exceptions (if installed). + Pass EXCCAUSE in a2, and check result in a2 (if -1, skip default handling). + */ + movi a4, _xt_intexc_hooks + l32i a4, a4, 0 /* user exception hook index 0 */ + beqz a4, 1f +.Ln_xt_user_exc_call_hook: + #ifdef __XTENSA_CALL0_ABI__ + callx0 a4 + beqi a2, -1, .L_xt_user_done + #else + mov a6, a2 + callx4 a4 + beqi a6, -1, .L_xt_user_done + mov a2, a6 + #endif +1: + #endif + + rsr a2, EXCCAUSE /* recover exc cause */ + movi a3, _xt_exception_table + get_percpu_entry_for a2, a4 + addx4 a4, a2, a3 /* a4 = address of exception table entry */ + l32i a4, a4, 0 /* a4 = handler address */ + #ifdef __XTENSA_CALL0_ABI__ + mov a2, sp /* a2 = pointer to exc frame */ + callx0 a4 /* call handler */ + #else + mov a6, sp /* a6 = pointer to exc frame */ + callx4 a4 /* call handler */ + #endif + +.L_xt_user_done: + + /* Restore context and return */ + call0 _xt_context_restore + l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ + wsr a0, PS + l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ + wsr a0, EPC_1 + l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ + l32i sp, sp, XT_STK_A1 /* remove exception frame */ + rsync /* ensure PS and EPC written */ + rfe /* PS.EXCM is cleared */ + + +/* +-------------------------------------------------------------------------------- + Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT + on entry and used to return to a thread or interrupted interrupt handler. +-------------------------------------------------------------------------------- +*/ + + .global _xt_user_exit + .type _xt_user_exit,@function + .align 4 +_xt_user_exit: + l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ + wsr a0, PS + l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ + wsr a0, EPC_1 + l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ + l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */ + rsync /* ensure PS and EPC written */ + rfe /* PS.EXCM is cleared */ + + +/* + +-------------------------------------------------------------------------------- +Syscall Exception Handler (jumped to from User Exception Handler). +Syscall 0 is required to spill the register windows (no-op in Call 0 ABI). +Only syscall 0 is handled here. Other syscalls return -1 to caller in a2. +-------------------------------------------------------------------------------- +*/ + + .section .iram1,"ax" + .type _xt_syscall_exc,@function + .align 4 +_xt_syscall_exc: + + #ifdef __XTENSA_CALL0_ABI__ + /* + Save minimal regs for scratch. Syscall 0 does nothing in Call0 ABI. + Use a minimal stack frame (16B) to save A2 & A3 for scratch. + PS.EXCM could be cleared here, but unlikely to improve worst-case latency. + rsr a0, PS + addi a0, a0, -PS_EXCM_MASK + wsr a0, PS + */ + addi sp, sp, -16 + s32i a2, sp, 8 + s32i a3, sp, 12 + #else /* Windowed ABI */ + /* + Save necessary context and spill the register windows. + PS.EXCM is still set and must remain set until after the spill. + Reuse context save function though it saves more than necessary. + For this reason, a full interrupt stack frame is allocated. + */ + addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ + s32i a12, sp, XT_STK_A12 /* _xt_context_save requires A12- */ + s32i a13, sp, XT_STK_A13 /* A13 to have already been saved */ + call0 _xt_context_save + #endif + + /* + Grab the interruptee's PC and skip over the 'syscall' instruction. + If it's at the end of a zero-overhead loop and it's not on the last + iteration, decrement loop counter and skip to beginning of loop. + */ + rsr a2, EPC_1 /* a2 = PC of 'syscall' */ + addi a3, a2, 3 /* ++PC */ + #if XCHAL_HAVE_LOOPS + rsr a0, LEND /* if (PC == LEND */ + bne a3, a0, 1f + rsr a0, LCOUNT /* && LCOUNT != 0) */ + beqz a0, 1f /* { */ + addi a0, a0, -1 /* --LCOUNT */ + rsr a3, LBEG /* PC = LBEG */ + wsr a0, LCOUNT /* } */ + #endif +1: wsr a3, EPC_1 /* update PC */ + + /* Restore interruptee's context and return from exception. */ + #ifdef __XTENSA_CALL0_ABI__ + l32i a2, sp, 8 + l32i a3, sp, 12 + addi sp, sp, 16 + #else + call0 _xt_context_restore + addi sp, sp, XT_STK_FRMSZ + #endif + movi a0, -1 + movnez a2, a0, a2 /* return -1 if not syscall 0 */ + rsr a0, EXCSAVE_1 + rfe + +/* +-------------------------------------------------------------------------------- +Co-Processor Exception Handler (jumped to from User Exception Handler). +These exceptions are generated by co-processor instructions, which are only +allowed in thread code (not in interrupts or kernel code). This restriction is +deliberately imposed to reduce the burden of state-save/restore in interrupts. +-------------------------------------------------------------------------------- +*/ +#if XCHAL_CP_NUM > 0 + + .section .rodata, "a" + +/* Offset to CP n save area in thread's CP save area. */ + .global _xt_coproc_sa_offset + .type _xt_coproc_sa_offset,@object + .align 16 /* minimize crossing cache boundaries */ +_xt_coproc_sa_offset: + .word XT_CP0_SA, XT_CP1_SA, XT_CP2_SA, XT_CP3_SA + .word XT_CP4_SA, XT_CP5_SA, XT_CP6_SA, XT_CP7_SA + +/* Bitmask for CP n's CPENABLE bit. */ + .type _xt_coproc_mask,@object + .align 16,,8 /* try to keep it all in one cache line */ + .set i, 0 +_xt_coproc_mask: + .rept XCHAL_CP_MAX + .long (i<<16) | (1<= 2 + + .begin literal_prefix .Level2InterruptVector + .section .Level2InterruptVector.text, "ax" + .global _Level2Vector + .type _Level2Vector,@function + .align 4 +_Level2Vector: + wsr a0, EXCSAVE_2 /* preserve a0 */ + call0 _xt_medint2 /* load interrupt handler */ + /* never returns here - call0 is used as a jump (see note at top) */ + + .end literal_prefix + + .section .iram1,"ax" + .type _xt_medint2,@function + .align 4 +_xt_medint2: + mov a0, sp /* sp == a1 */ + addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ + s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */ + rsr a0, EPS_2 /* save interruptee's PS */ + s32i a0, sp, XT_STK_PS + rsr a0, EPC_2 /* save interruptee's PC */ + s32i a0, sp, XT_STK_PC + rsr a0, EXCSAVE_2 /* save interruptee's a0 */ + s32i a0, sp, XT_STK_A0 + 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).*/ + #ifdef XT_DEBUG_BACKTRACE + #ifndef __XTENSA_CALL0_ABI__ + mov a0, sp + wsr a0, EXCSAVE_2 + #endif + #endif + + /* Save rest of interrupt context and enter RTOS. */ + call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */ + + /* !! We are now on the RTOS system stack !! */ + + /* Set up PS for C, enable interrupts above this level and clear EXCM. */ + #ifdef __XTENSA_CALL0_ABI__ + movi a0, PS_INTLEVEL(2) | PS_UM + #else + movi a0, PS_INTLEVEL(2) | PS_UM | PS_WOE + #endif + wsr a0, PS + rsync + + /* OK to call C code at this point, dispatch user ISRs */ + + dispatch_c_isr 2 XCHAL_INTLEVEL2_MASK + + /* Done handling interrupts, transfer control to OS */ + call0 XT_RTOS_INT_EXIT /* does not return directly here */ + + /* + Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT + on entry and used to return to a thread or interrupted interrupt handler. + */ + .global _xt_medint2_exit + .type _xt_medint2_exit,@function + .align 4 +_xt_medint2_exit: + /* Restore only level-specific regs (the rest were already restored) */ + l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ + wsr a0, EPS_2 + l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ + wsr a0, EPC_2 + l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ + l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */ + rsync /* ensure EPS and EPC written */ + rfi 2 + +#endif /* Level 2 */ + +#if XCHAL_EXCM_LEVEL >= 3 + + .begin literal_prefix .Level3InterruptVector + .section .Level3InterruptVector.text, "ax" + .global _Level3Vector + .type _Level3Vector,@function + .align 4 +_Level3Vector: + wsr a0, EXCSAVE_3 /* preserve a0 */ + call0 _xt_medint3 /* load interrupt handler */ + /* never returns here - call0 is used as a jump (see note at top) */ + + .end literal_prefix + + .section .iram1,"ax" + .type _xt_medint3,@function + .align 4 +_xt_medint3: + mov a0, sp /* sp == a1 */ + addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ + s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */ + rsr a0, EPS_3 /* save interruptee's PS */ + s32i a0, sp, XT_STK_PS + rsr a0, EPC_3 /* save interruptee's PC */ + s32i a0, sp, XT_STK_PC + rsr a0, EXCSAVE_3 /* save interruptee's a0 */ + s32i a0, sp, XT_STK_A0 + 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).*/ + #ifdef XT_DEBUG_BACKTRACE + #ifndef __XTENSA_CALL0_ABI__ + mov a0, sp + wsr a0, EXCSAVE_3 + #endif + #endif + + /* Save rest of interrupt context and enter RTOS. */ + call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */ + + /* !! We are now on the RTOS system stack !! */ + + /* Set up PS for C, enable interrupts above this level and clear EXCM. */ + #ifdef __XTENSA_CALL0_ABI__ + movi a0, PS_INTLEVEL(3) | PS_UM + #else + movi a0, PS_INTLEVEL(3) | PS_UM | PS_WOE + #endif + wsr a0, PS + rsync + + /* OK to call C code at this point, dispatch user ISRs */ + + dispatch_c_isr 3 XCHAL_INTLEVEL3_MASK + + /* Done handling interrupts, transfer control to OS */ + call0 XT_RTOS_INT_EXIT /* does not return directly here */ + + /* + Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT + on entry and used to return to a thread or interrupted interrupt handler. + */ + .global _xt_medint3_exit + .type _xt_medint3_exit,@function + .align 4 +_xt_medint3_exit: + /* Restore only level-specific regs (the rest were already restored) */ + l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ + wsr a0, EPS_3 + l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ + wsr a0, EPC_3 + l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ + l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */ + rsync /* ensure EPS and EPC written */ + rfi 3 + +#endif /* Level 3 */ + +#if XCHAL_EXCM_LEVEL >= 4 + + .begin literal_prefix .Level4InterruptVector + .section .Level4InterruptVector.text, "ax" + .global _Level4Vector + .type _Level4Vector,@function + .align 4 +_Level4Vector: + wsr a0, EXCSAVE_4 /* preserve a0 */ + call0 _xt_medint4 /* load interrupt handler */ + + .end literal_prefix + + .section .iram1,"ax" + .type _xt_medint4,@function + .align 4 +_xt_medint4: + mov a0, sp /* sp == a1 */ + addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ + s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */ + rsr a0, EPS_4 /* save interruptee's PS */ + s32i a0, sp, XT_STK_PS + rsr a0, EPC_4 /* save interruptee's PC */ + s32i a0, sp, XT_STK_PC + rsr a0, EXCSAVE_4 /* save interruptee's a0 */ + s32i a0, sp, XT_STK_A0 + 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).*/ + #ifdef XT_DEBUG_BACKTRACE + #ifndef __XTENSA_CALL0_ABI__ + mov a0, sp + wsr a0, EXCSAVE_4 + #endif + #endif + + /* Save rest of interrupt context and enter RTOS. */ + call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */ + + /* !! We are now on the RTOS system stack !! */ + + /* Set up PS for C, enable interrupts above this level and clear EXCM. */ + #ifdef __XTENSA_CALL0_ABI__ + movi a0, PS_INTLEVEL(4) | PS_UM + #else + movi a0, PS_INTLEVEL(4) | PS_UM | PS_WOE + #endif + wsr a0, PS + rsync + + /* OK to call C code at this point, dispatch user ISRs */ + + dispatch_c_isr 4 XCHAL_INTLEVEL4_MASK + + /* Done handling interrupts, transfer control to OS */ + call0 XT_RTOS_INT_EXIT /* does not return directly here */ + + /* + Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT + on entry and used to return to a thread or interrupted interrupt handler. + */ + .global _xt_medint4_exit + .type _xt_medint4_exit,@function + .align 4 +_xt_medint4_exit: + /* Restore only level-specific regs (the rest were already restored) */ + l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ + wsr a0, EPS_4 + l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ + wsr a0, EPC_4 + l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ + l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */ + rsync /* ensure EPS and EPC written */ + rfi 4 + +#endif /* Level 4 */ + +#if XCHAL_EXCM_LEVEL >= 5 + + .begin literal_prefix .Level5InterruptVector + .section .Level5InterruptVector.text, "ax" + .global _Level5Vector + .type _Level5Vector,@function + .align 4 +_Level5Vector: + wsr a0, EXCSAVE_5 /* preserve a0 */ + call0 _xt_medint5 /* load interrupt handler */ + + .end literal_prefix + + .section .iram1,"ax" + .type _xt_medint5,@function + .align 4 +_xt_medint5: + mov a0, sp /* sp == a1 */ + addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ + s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */ + rsr a0, EPS_5 /* save interruptee's PS */ + s32i a0, sp, XT_STK_PS + rsr a0, EPC_5 /* save interruptee's PC */ + s32i a0, sp, XT_STK_PC + rsr a0, EXCSAVE_5 /* save interruptee's a0 */ + s32i a0, sp, XT_STK_A0 + 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).*/ + #ifdef XT_DEBUG_BACKTRACE + #ifndef __XTENSA_CALL0_ABI__ + mov a0, sp + wsr a0, EXCSAVE_5 + #endif + #endif + + /* Save rest of interrupt context and enter RTOS. */ + call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */ + + /* !! We are now on the RTOS system stack !! */ + + /* Set up PS for C, enable interrupts above this level and clear EXCM. */ + #ifdef __XTENSA_CALL0_ABI__ + movi a0, PS_INTLEVEL(5) | PS_UM + #else + movi a0, PS_INTLEVEL(5) | PS_UM | PS_WOE + #endif + wsr a0, PS + rsync + + /* OK to call C code at this point, dispatch user ISRs */ + + dispatch_c_isr 5 XCHAL_INTLEVEL5_MASK + + /* Done handling interrupts, transfer control to OS */ + call0 XT_RTOS_INT_EXIT /* does not return directly here */ + + /* + Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT + on entry and used to return to a thread or interrupted interrupt handler. + */ + .global _xt_medint5_exit + .type _xt_medint5_exit,@function + .align 4 +_xt_medint5_exit: + /* Restore only level-specific regs (the rest were already restored) */ + l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ + wsr a0, EPS_5 + l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ + wsr a0, EPC_5 + l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ + l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */ + rsync /* ensure EPS and EPC written */ + rfi 5 + +#endif /* Level 5 */ + +#if XCHAL_EXCM_LEVEL >= 6 + + .begin literal_prefix .Level6InterruptVector + .section .Level6InterruptVector.text, "ax" + .global _Level6Vector + .type _Level6Vector,@function + .align 4 +_Level6Vector: + wsr a0, EXCSAVE_6 /* preserve a0 */ + call0 _xt_medint6 /* load interrupt handler */ + + .end literal_prefix + + .section .iram1,"ax" + .type _xt_medint6,@function + .align 4 +_xt_medint6: + mov a0, sp /* sp == a1 */ + addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ + s32i a0, sp, XT_STK_A1 /* save pre-interrupt SP */ + rsr a0, EPS_6 /* save interruptee's PS */ + s32i a0, sp, XT_STK_PS + rsr a0, EPC_6 /* save interruptee's PC */ + s32i a0, sp, XT_STK_PC + rsr a0, EXCSAVE_6 /* save interruptee's a0 */ + s32i a0, sp, XT_STK_A0 + 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).*/ + #ifdef XT_DEBUG_BACKTRACE + #ifndef __XTENSA_CALL0_ABI__ + mov a0, sp + wsr a0, EXCSAVE_6 + #endif + #endif + + /* Save rest of interrupt context and enter RTOS. */ + call0 XT_RTOS_INT_ENTER /* common RTOS interrupt entry */ + + /* !! We are now on the RTOS system stack !! */ + + /* Set up PS for C, enable interrupts above this level and clear EXCM. */ + #ifdef __XTENSA_CALL0_ABI__ + movi a0, PS_INTLEVEL(6) | PS_UM + #else + movi a0, PS_INTLEVEL(6) | PS_UM | PS_WOE + #endif + wsr a0, PS + rsync + + /* OK to call C code at this point, dispatch user ISRs */ + + dispatch_c_isr 6 XCHAL_INTLEVEL6_MASK + + /* Done handling interrupts, transfer control to OS */ + call0 XT_RTOS_INT_EXIT /* does not return directly here */ + + /* + Exit point for dispatch. Saved in interrupt stack frame at XT_STK_EXIT + on entry and used to return to a thread or interrupted interrupt handler. + */ + .global _xt_medint6_exit + .type _xt_medint6_exit,@function + .align 4 +_xt_medint6_exit: + /* Restore only level-specific regs (the rest were already restored) */ + l32i a0, sp, XT_STK_PS /* retrieve interruptee's PS */ + wsr a0, EPS_6 + l32i a0, sp, XT_STK_PC /* retrieve interruptee's PC */ + wsr a0, EPC_6 + l32i a0, sp, XT_STK_A0 /* retrieve interruptee's A0 */ + l32i sp, sp, XT_STK_A1 /* remove interrupt stack frame */ + rsync /* ensure EPS and EPC written */ + rfi 6 + +#endif /* Level 6 */ + + +/******************************************************************************* + +HIGH PRIORITY (LEVEL > XCHAL_EXCM_LEVEL) INTERRUPT VECTORS AND HANDLERS + +High priority interrupts are by definition those with priorities greater +than XCHAL_EXCM_LEVEL. This includes non-maskable (NMI). High priority +interrupts cannot interact with the RTOS, that is they must save all regs +they use and not call any RTOS function. + +A further restriction imposed by the Xtensa windowed architecture is that +high priority interrupts must not modify the stack area even logically +"above" the top of the interrupted stack (they need to provide their +own stack or static save area). + +Cadence Design Systems recommends high priority interrupt handlers be coded in assembly +and used for purposes requiring very short service times. + +Here are templates for high priority (level 2+) interrupt vectors. +They assume only one interrupt per level to avoid the burden of identifying +which interrupts at this level are pending and enabled. This allows for +minimum latency and avoids having to save/restore a2 in addition to a0. +If more than one interrupt per high priority level is configured, this burden +is on the handler which in any case must provide a way to save and restore +registers it uses without touching the interrupted stack. + +Each vector goes at a predetermined location according to the Xtensa +hardware configuration, which is ensured by its placement in a special +section known to the Xtensa linker support package (LSP). It performs +the minimum necessary before jumping to the handler in the .text section. + +*******************************************************************************/ + +/* +These stubs just call xt_highintX/xt_nmi to handle the real interrupt. Please define +these in an external assembly source file. If these symbols are not defined anywhere +else, the defaults in xtensa_vector_defaults.S are used. +*/ + +#if XCHAL_NUM_INTLEVELS >=2 && XCHAL_EXCM_LEVEL <2 && XCHAL_DEBUGLEVEL !=2 + + .begin literal_prefix .Level2InterruptVector + .section .Level2InterruptVector.text, "ax" + .global _Level2Vector + .type _Level2Vector,@function + .global xt_highint2 + .align 4 +_Level2Vector: + wsr a0, EXCSAVE_2 /* preserve a0 */ + call0 xt_highint2 /* load interrupt handler */ + + .end literal_prefix + +#endif /* Level 2 */ + +#if XCHAL_NUM_INTLEVELS >=3 && XCHAL_EXCM_LEVEL <3 && XCHAL_DEBUGLEVEL !=3 + + .begin literal_prefix .Level3InterruptVector + .section .Level3InterruptVector.text, "ax" + .global _Level3Vector + .type _Level3Vector,@function + .global xt_highint3 + .align 4 +_Level3Vector: + wsr a0, EXCSAVE_3 /* preserve a0 */ + call0 xt_highint3 /* load interrupt handler */ + /* never returns here - call0 is used as a jump (see note at top) */ + + .end literal_prefix + +#endif /* Level 3 */ + +#if XCHAL_NUM_INTLEVELS >=4 && XCHAL_EXCM_LEVEL <4 && XCHAL_DEBUGLEVEL !=4 + + .begin literal_prefix .Level4InterruptVector + .section .Level4InterruptVector.text, "ax" + .global _Level4Vector + .type _Level4Vector,@function + .global xt_highint4 + .align 4 +_Level4Vector: + wsr a0, EXCSAVE_4 /* preserve a0 */ + call0 xt_highint4 /* load interrupt handler */ + /* never returns here - call0 is used as a jump (see note at top) */ + + .end literal_prefix + +#endif /* Level 4 */ + +#if XCHAL_NUM_INTLEVELS >=5 && XCHAL_EXCM_LEVEL <5 && XCHAL_DEBUGLEVEL !=5 + + .begin literal_prefix .Level5InterruptVector + .section .Level5InterruptVector.text, "ax" + .global _Level5Vector + .type _Level5Vector,@function + .global xt_highint5 + .align 4 +_Level5Vector: + wsr a0, EXCSAVE_5 /* preserve a0 */ + call0 xt_highint5 /* load interrupt handler */ + /* never returns here - call0 is used as a jump (see note at top) */ + + .end literal_prefix + +#endif /* Level 5 */ + +#if XCHAL_NUM_INTLEVELS >=6 && XCHAL_EXCM_LEVEL <6 && XCHAL_DEBUGLEVEL !=6 + + .begin literal_prefix .Level6InterruptVector + .section .Level6InterruptVector.text, "ax" + .global _Level6Vector + .type _Level6Vector,@function + .global xt_highint6 + .align 4 +_Level6Vector: + wsr a0, EXCSAVE_6 /* preserve a0 */ + call0 xt_highint6 /* load interrupt handler */ + /* never returns here - call0 is used as a jump (see note at top) */ + + .end literal_prefix + +#endif /* Level 6 */ + +#if XCHAL_HAVE_NMI + + .begin literal_prefix .NMIExceptionVector + .section .NMIExceptionVector.text, "ax" + .global _NMIExceptionVector + .type _NMIExceptionVector,@function + .global xt_nmi + .align 4 +_NMIExceptionVector: + wsr a0, EXCSAVE + XCHAL_NMILEVEL _ /* preserve a0 */ + call0 xt_nmi /* load interrupt handler */ + /* never returns here - call0 is used as a jump (see note at top) */ + + .end literal_prefix + +#endif /* NMI */ + + +/******************************************************************************* + +WINDOW OVERFLOW AND UNDERFLOW EXCEPTION VECTORS AND ALLOCA EXCEPTION HANDLER + +Here is the code for each window overflow/underflow exception vector and +(interspersed) efficient code for handling the alloca exception cause. +Window exceptions are handled entirely in the vector area and are very +tight for performance. The alloca exception is also handled entirely in +the window vector area so comes at essentially no cost in code size. +Users should never need to modify them and Cadence Design Systems recommends +they do not. + +Window handlers go at predetermined vector locations according to the +Xtensa hardware configuration, which is ensured by their placement in a +special section known to the Xtensa linker support package (LSP). Since +their offsets in that section are always the same, the LSPs do not define +a section per vector. + +These things are coded for XEA2 only (XEA1 is not supported). + +Note on Underflow Handlers: +The underflow handler for returning from call[i+1] to call[i] +must preserve all the registers from call[i+1]'s window. +In particular, a0 and a1 must be preserved because the RETW instruction +will be reexecuted (and may even underflow if an intervening exception +has flushed call[i]'s registers). +Registers a2 and up may contain return values. + +*******************************************************************************/ + +#if XCHAL_HAVE_WINDOWED + + .section .WindowVectors.text, "ax" + +/* +-------------------------------------------------------------------------------- +Window Overflow Exception for Call4. + +Invoked if a call[i] referenced a register (a4-a15) +that contains data from ancestor call[j]; +call[j] had done a call4 to call[j+1]. +On entry here: + window rotated to call[j] start point; + a0-a3 are registers to be saved; + a4-a15 must be preserved; + a5 is call[j+1]'s stack pointer. +-------------------------------------------------------------------------------- +*/ + + .org 0x0 + .global _WindowOverflow4 +_WindowOverflow4: + + s32e a0, a5, -16 /* save a0 to call[j+1]'s stack frame */ + s32e a1, a5, -12 /* save a1 to call[j+1]'s stack frame */ + s32e a2, a5, -8 /* save a2 to call[j+1]'s stack frame */ + s32e a3, a5, -4 /* save a3 to call[j+1]'s stack frame */ + rfwo /* rotates back to call[i] position */ + +/* +-------------------------------------------------------------------------------- +Window Underflow Exception for Call4 + +Invoked by RETW returning from call[i+1] to call[i] +where call[i]'s registers must be reloaded (not live in ARs); +where call[i] had done a call4 to call[i+1]. +On entry here: + window rotated to call[i] start point; + a0-a3 are undefined, must be reloaded with call[i].reg[0..3]; + a4-a15 must be preserved (they are call[i+1].reg[0..11]); + a5 is call[i+1]'s stack pointer. +-------------------------------------------------------------------------------- +*/ + + .org 0x40 + .global _WindowUnderflow4 +_WindowUnderflow4: + + l32e a0, a5, -16 /* restore a0 from call[i+1]'s stack frame */ + l32e a1, a5, -12 /* restore a1 from call[i+1]'s stack frame */ + l32e a2, a5, -8 /* restore a2 from call[i+1]'s stack frame */ + l32e a3, a5, -4 /* restore a3 from call[i+1]'s stack frame */ + rfwu + +/* +-------------------------------------------------------------------------------- +Handle alloca exception generated by interruptee executing 'movsp'. +This uses space between the window vectors, so is essentially "free". +All interruptee's regs are intact except a0 which is saved in EXCSAVE_1, +and PS.EXCM has been set by the exception hardware (can't be interrupted). +The fact the alloca exception was taken means the registers associated with +the base-save area have been spilled and will be restored by the underflow +handler, so those 4 registers are available for scratch. +The code is optimized to avoid unaligned branches and minimize cache misses. +-------------------------------------------------------------------------------- +*/ + + .align 4 + .global _xt_alloca_exc +_xt_alloca_exc: + + rsr a0, WINDOWBASE /* grab WINDOWBASE before rotw changes it */ + rotw -1 /* WINDOWBASE goes to a4, new a0-a3 are scratch */ + rsr a2, PS + extui a3, a2, XCHAL_PS_OWB_SHIFT, XCHAL_PS_OWB_BITS + xor a3, a3, a4 /* bits changed from old to current windowbase */ + rsr a4, EXCSAVE_1 /* restore original a0 (now in a4) */ + slli a3, a3, XCHAL_PS_OWB_SHIFT + xor a2, a2, a3 /* flip changed bits in old window base */ + wsr a2, PS /* update PS.OWB to new window base */ + rsync + + _bbci.l a4, 31, _WindowUnderflow4 + rotw -1 /* original a0 goes to a8 */ + _bbci.l a8, 30, _WindowUnderflow8 + rotw -1 + j _WindowUnderflow12 + +/* +-------------------------------------------------------------------------------- +Window Overflow Exception for Call8 + +Invoked if a call[i] referenced a register (a4-a15) +that contains data from ancestor call[j]; +call[j] had done a call8 to call[j+1]. +On entry here: + window rotated to call[j] start point; + a0-a7 are registers to be saved; + a8-a15 must be preserved; + a9 is call[j+1]'s stack pointer. +-------------------------------------------------------------------------------- +*/ + + .org 0x80 + .global _WindowOverflow8 +_WindowOverflow8: + + s32e a0, a9, -16 /* save a0 to call[j+1]'s stack frame */ + l32e a0, a1, -12 /* a0 <- call[j-1]'s sp + (used to find end of call[j]'s frame) */ + s32e a1, a9, -12 /* save a1 to call[j+1]'s stack frame */ + s32e a2, a9, -8 /* save a2 to call[j+1]'s stack frame */ + s32e a3, a9, -4 /* save a3 to call[j+1]'s stack frame */ + s32e a4, a0, -32 /* save a4 to call[j]'s stack frame */ + s32e a5, a0, -28 /* save a5 to call[j]'s stack frame */ + s32e a6, a0, -24 /* save a6 to call[j]'s stack frame */ + s32e a7, a0, -20 /* save a7 to call[j]'s stack frame */ + rfwo /* rotates back to call[i] position */ + +/* +-------------------------------------------------------------------------------- +Window Underflow Exception for Call8 + +Invoked by RETW returning from call[i+1] to call[i] +where call[i]'s registers must be reloaded (not live in ARs); +where call[i] had done a call8 to call[i+1]. +On entry here: + window rotated to call[i] start point; + a0-a7 are undefined, must be reloaded with call[i].reg[0..7]; + a8-a15 must be preserved (they are call[i+1].reg[0..7]); + a9 is call[i+1]'s stack pointer. +-------------------------------------------------------------------------------- +*/ + + .org 0xC0 + .global _WindowUnderflow8 +_WindowUnderflow8: + + l32e a0, a9, -16 /* restore a0 from call[i+1]'s stack frame */ + l32e a1, a9, -12 /* restore a1 from call[i+1]'s stack frame */ + l32e a2, a9, -8 /* restore a2 from call[i+1]'s stack frame */ + l32e a7, a1, -12 /* a7 <- call[i-1]'s sp + (used to find end of call[i]'s frame) */ + l32e a3, a9, -4 /* restore a3 from call[i+1]'s stack frame */ + l32e a4, a7, -32 /* restore a4 from call[i]'s stack frame */ + l32e a5, a7, -28 /* restore a5 from call[i]'s stack frame */ + l32e a6, a7, -24 /* restore a6 from call[i]'s stack frame */ + l32e a7, a7, -20 /* restore a7 from call[i]'s stack frame */ + rfwu + +/* +-------------------------------------------------------------------------------- +Window Overflow Exception for Call12 + +Invoked if a call[i] referenced a register (a4-a15) +that contains data from ancestor call[j]; +call[j] had done a call12 to call[j+1]. +On entry here: + window rotated to call[j] start point; + a0-a11 are registers to be saved; + a12-a15 must be preserved; + a13 is call[j+1]'s stack pointer. +-------------------------------------------------------------------------------- +*/ + + .org 0x100 + .global _WindowOverflow12 +_WindowOverflow12: + + s32e a0, a13, -16 /* save a0 to call[j+1]'s stack frame */ + l32e a0, a1, -12 /* a0 <- call[j-1]'s sp + (used to find end of call[j]'s frame) */ + s32e a1, a13, -12 /* save a1 to call[j+1]'s stack frame */ + s32e a2, a13, -8 /* save a2 to call[j+1]'s stack frame */ + s32e a3, a13, -4 /* save a3 to call[j+1]'s stack frame */ + s32e a4, a0, -48 /* save a4 to end of call[j]'s stack frame */ + s32e a5, a0, -44 /* save a5 to end of call[j]'s stack frame */ + s32e a6, a0, -40 /* save a6 to end of call[j]'s stack frame */ + s32e a7, a0, -36 /* save a7 to end of call[j]'s stack frame */ + s32e a8, a0, -32 /* save a8 to end of call[j]'s stack frame */ + s32e a9, a0, -28 /* save a9 to end of call[j]'s stack frame */ + s32e a10, a0, -24 /* save a10 to end of call[j]'s stack frame */ + s32e a11, a0, -20 /* save a11 to end of call[j]'s stack frame */ + rfwo /* rotates back to call[i] position */ + +/* +-------------------------------------------------------------------------------- +Window Underflow Exception for Call12 + +Invoked by RETW returning from call[i+1] to call[i] +where call[i]'s registers must be reloaded (not live in ARs); +where call[i] had done a call12 to call[i+1]. +On entry here: + window rotated to call[i] start point; + a0-a11 are undefined, must be reloaded with call[i].reg[0..11]; + a12-a15 must be preserved (they are call[i+1].reg[0..3]); + a13 is call[i+1]'s stack pointer. +-------------------------------------------------------------------------------- +*/ + + .org 0x140 + .global _WindowUnderflow12 +_WindowUnderflow12: + + l32e a0, a13, -16 /* restore a0 from call[i+1]'s stack frame */ + l32e a1, a13, -12 /* restore a1 from call[i+1]'s stack frame */ + l32e a2, a13, -8 /* restore a2 from call[i+1]'s stack frame */ + l32e a11, a1, -12 /* a11 <- call[i-1]'s sp + (used to find end of call[i]'s frame) */ + l32e a3, a13, -4 /* restore a3 from call[i+1]'s stack frame */ + l32e a4, a11, -48 /* restore a4 from end of call[i]'s stack frame */ + l32e a5, a11, -44 /* restore a5 from end of call[i]'s stack frame */ + l32e a6, a11, -40 /* restore a6 from end of call[i]'s stack frame */ + l32e a7, a11, -36 /* restore a7 from end of call[i]'s stack frame */ + l32e a8, a11, -32 /* restore a8 from end of call[i]'s stack frame */ + l32e a9, a11, -28 /* restore a9 from end of call[i]'s stack frame */ + l32e a10, a11, -24 /* restore a10 from end of call[i]'s stack frame */ + l32e a11, a11, -20 /* restore a11 from end of call[i]'s stack frame */ + rfwu + +#endif /* XCHAL_HAVE_WINDOWED */ + + .section .UserEnter.text, "ax" + .global call_user_start + .type call_user_start,@function + .align 4 + .literal_position