diff --git a/components/freertos/CMakeLists.txt b/components/freertos/CMakeLists.txt index f3ab5a11e2..adf4dd7460 100644 --- a/components/freertos/CMakeLists.txt +++ b/components/freertos/CMakeLists.txt @@ -28,6 +28,24 @@ if(CONFIG_FREERTOS_SMP) "FreeRTOS-Kernel-SMP/portable/xtensa/include/freertos" "FreeRTOS-Kernel-SMP/portable/xtensa" .) + + elseif(CONFIG_IDF_TARGET_ARCH_RISCV) + set(srcs + "FreeRTOS-Kernel-SMP/portable/riscv/port.c" + "FreeRTOS-Kernel-SMP/portable/riscv/portasm.S") + + set(include_dirs + FreeRTOS-Kernel-SMP/include + esp_additions/include/freertos # For files with #include "FreeRTOSConfig.h" + FreeRTOS-Kernel-SMP/portable/riscv/include + esp_additions/include # For files with #include "freertos/FreeRTOSConfig.h" + FreeRTOS-Kernel-SMP/portable/riscv/include/freertos) + + set(private_include_dirs + FreeRTOS-Kernel-SMP/portable/riscv/include/freertos + FreeRTOS-Kernel-SMP/portable/riscv + .) + endif() list(APPEND srcs diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/include/freertos/FreeRTOSConfig_smp.h b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/include/freertos/FreeRTOSConfig_smp.h new file mode 100644 index 0000000000..511ac13fd9 --- /dev/null +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/include/freertos/FreeRTOSConfig_smp.h @@ -0,0 +1,328 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef FREERTOS_CONFIG_SMP_H +#define FREERTOS_CONFIG_SMP_H + +#include "sdkconfig.h" + +/* +This file get's pulled into assembly sources. Therefore, some includes need to be wrapped in #ifndef __ASSEMBLER__ +*/ + +#ifndef __ASSEMBLER__ +#include //For configASSERT() +#endif /* def __ASSEMBLER__ */ + +#if __XTENSA__ +/* Required for configuration-dependent settings. */ +#include "xtensa_config.h" + +/* -------------------------------------------- Xtensa Additional Config ---------------------------------------------- + * - Provide Xtensa definitions usually given by -D option when building with xt-make (see readme_xtensa.txt) + * - xtensa_rtos.h and xtensa_timer.h will default some of these values + * - XT_SIMULATOR configXT_SIMULATOR + * - XT_BOARD configXT_BOARD + * - XT_CLOCK_FREQ Should not be defined as we are using XT_BOARD mode + * - XT_TICK_PER_SEC Defaults to configTICK_RATE_HZ + * - XT_TIMER_INDEX Defaults to configXT_TIMER_INDEX + * - XT_INTEXC_HOOKS Defaults to configXT_INTEXC_HOOKS + * - XT_USE_OVLY We don't define this (unused) + * - XT_USE_SWPRI We don't define this (unused) + * ------------------------------------------------------------------------------------------------------------------ */ + +#define configXT_SIMULATOR 0 +#define configXT_BOARD 1 /* Board mode */ +#if CONFIG_FREERTOS_CORETIMER_0 +#define configXT_TIMER_INDEX 0 +#elif CONFIG_FREERTOS_CORETIMER_1 +#define configXT_TIMER_INDEX 1 +#endif +#define configXT_INTEXC_HOOKS 0 + +#define configBENCHMARK 0 +#endif // __XTENSA__ + +/* ------------------------------------------------ ESP-IDF Additions -------------------------------------------------- + * + * ------------------------------------------------------------------------------------------------------------------ */ + +#if __XTENSA__ +/* The Xtensa port uses a separate interrupt stack. Adjust the stack size + * to suit the needs of your specific application. + * Size needs to be aligned to the stack increment, since the location of + * the stack for the 2nd CPU will be calculated using configISR_STACK_SIZE. + */ +#define configSTACK_ALIGNMENT 16 +#ifndef configISR_STACK_SIZE +#define configISR_STACK_SIZE ((CONFIG_FREERTOS_ISR_STACKSIZE + configSTACK_ALIGNMENT - 1) & (~(configSTACK_ALIGNMENT - 1))) +#endif +#else // RISC-V +#ifndef configISR_STACK_SIZE +#define configISR_STACK_SIZE (CONFIG_FREERTOS_ISR_STACKSIZE) +#endif +#endif // __XTENSA__ +/* ----------------------------------------------------- Helpers ------------------------------------------------------- + * - Macros that the FreeRTOS configuration macros depend on + * ------------------------------------------------------------------------------------------------------------------ */ + +/* Higher stack checker modes cause overhead on each function call */ +#if CONFIG_STACK_CHECK_ALL || CONFIG_STACK_CHECK_STRONG +#define STACK_OVERHEAD_CHECKER 256 +#else +#define STACK_OVERHEAD_CHECKER 0 +#endif + +/* with optimizations disabled, scheduler uses additional stack */ +#if CONFIG_COMPILER_OPTIMIZATION_NONE +#define STACK_OVERHEAD_OPTIMIZATION 320 +#else +#define STACK_OVERHEAD_OPTIMIZATION 0 +#endif + +/* apptrace mdule increases minimum stack usage */ +#if CONFIG_APPTRACE_ENABLE +#define STACK_OVERHEAD_APPTRACE 1280 +#else +#define STACK_OVERHEAD_APPTRACE 0 +#endif + +/* Stack watchpoint decreases minimum usable stack size by up to 60 bytes. + See FreeRTOS FREERTOS_WATCHPOINT_END_OF_STACK option in Kconfig. */ +#if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK +#define STACK_OVERHEAD_WATCHPOINT 60 +#else +#define STACK_OVERHEAD_WATCHPOINT 0 +#endif + +#define configSTACK_OVERHEAD_TOTAL ( \ + STACK_OVERHEAD_CHECKER + \ + STACK_OVERHEAD_OPTIMIZATION + \ + STACK_OVERHEAD_APPTRACE + \ + STACK_OVERHEAD_WATCHPOINT \ + ) + +/* ----------------------------------------------------- Helpers ------------------------------------------------------- + * - Macros that the FreeRTOS configuration macros depend on + * ------------------------------------------------------------------------------------------------------------------ */ + + +/* ------------------------------------------------- FreeRTOS Config --------------------------------------------------- + * - All Vanilla FreeRTOS configuration goes into this section + * - Keep this section in-sync with the corresponding version of single-core upstream version of FreeRTOS + * - Don't put any SMP or ESP-IDF exclusive FreeRTOS configurations here. Those go into the next section + * - Not all FreeRTOS configuration are listed. Some configurations have default values set in FreeRTOS.h thus don't + * need to be explicitly defined. + * ------------------------------------------------------------------------------------------------------------------ */ + +/*----------------------------------------------------------- + * Application specific definitions. + * + * These definitions should be adjusted for your particular hardware and + * application requirements. + * + * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * + * See http://www.freertos.org/a00110.html + *----------------------------------------------------------*/ + +// ------------------ Scheduler Related -------------------- + +#define configUSE_PREEMPTION 1 +#define configUSE_TASK_PREEMPTION_DISABLE 1 +#define configUSE_TICKLESS_IDLE 0 +#define configCPU_CLOCK_HZ (CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ * 1000000) +#define configTICK_RATE_HZ CONFIG_FREERTOS_HZ +#define configMAX_PRIORITIES ( 25 ) //This has impact on speed of search for highest priority +#define configMINIMAL_STACK_SIZE ( 768 + configSTACK_OVERHEAD_TOTAL ) +#define configUSE_TIME_SLICING 1 +#define configUSE_16_BIT_TICKS 0 +#define configIDLE_SHOULD_YIELD 0 //Todo: Check this +#define configKERNEL_INTERRUPT_PRIORITY 1 //Todo: This currently isn't used anywhere +#if __XTENSA__ +#define configMAX_API_CALL_INTERRUPT_PRIORITY XCHAL_EXCM_LEVEL +#else // RISC-V +#define configMAX_API_CALL_INTERRUPT_PRIORITY 0 +#endif // __XTENSA__ +#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0 //SMP currently does not support optimized selection + +// -------------------- FreeRTOS SMP ----------------------- + +#ifdef CONFIG_FREERTOS_UNICORE +#define configNUM_CORES 1 +#else +#define configNUM_CORES 2 +#endif +#define configUSE_CORE_AFFINITY 1 +#define configRUN_MULTIPLE_PRIORITIES 1 +#define configUSE_MINIMAL_IDLE_HOOK 1 // This is always enabled to call IDF style idle hooks, by can be "--Wl,--wrap" if users enable CONFIG_FREERTOS_USE_MINIMAL_IDLE_HOOK + +// ------------- Synchronization Primitives ---------------- + +#define configUSE_MUTEXES 1 +#define configUSE_RECURSIVE_MUTEXES 1 +#define configUSE_COUNTING_SEMAPHORES 1 +#define configUSE_QUEUE_SETS 1 +#define configQUEUE_REGISTRY_SIZE CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE +#define configUSE_TASK_NOTIFICATIONS 1 +#define configTASK_NOTIFICATION_ARRAY_ENTRIES 1 + +// ----------------------- System -------------------------- + +#define configMAX_TASK_NAME_LEN CONFIG_FREERTOS_MAX_TASK_NAME_LEN + +#if ( CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS ) +/* If thread local storage pointer deletion callbacks are registered + * then we double the storage space reserved for the thread local + * storage pointers in the task TCB. The first half of the storage area + * is used to store the TLS pointers themselves while the second half + * is used to store the respective deletion callbacks. + */ +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS ( CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS * 2 ) +#else +#define configNUM_THREAD_LOCAL_STORAGE_POINTERS CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS +#endif // CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS +#define configSTACK_DEPTH_TYPE uint32_t +#define configUSE_NEWLIB_REENTRANT 1 +#define configENABLE_BACKWARD_COMPATIBILITY 0 +#define configASSERT(a) assert(a) +#define configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H 1 + +// ----------------------- Memory ------------------------- + +#define configSUPPORT_STATIC_ALLOCATION 1 +#define configSUPPORT_DYNAMIC_ALLOCATION 1 +//We define the heap to span all of the non-statically-allocated shared RAM. ToDo: Make sure there +//is some space left for the app and main cpu when running outside of a thread. +#define configTOTAL_HEAP_SIZE (&_heap_end - &_heap_start)//( ( size_t ) (64 * 1024) ) +#define configAPPLICATION_ALLOCATED_HEAP 1 +#define configSTACK_ALLOCATION_FROM_SEPARATE_HEAP 0 //Todo: Check this + +// ------------------------ Hooks -------------------------- + +#if CONFIG_FREERTOS_USE_IDLE_HOOK +#define configUSE_IDLE_HOOK 1 +#else +#define configUSE_IDLE_HOOK 0 +#endif +#define configUSE_TICK_HOOK 1 +#if CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE +#define configCHECK_FOR_STACK_OVERFLOW 0 +#elif CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL +#define configCHECK_FOR_STACK_OVERFLOW 1 +#elif CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY +#define configCHECK_FOR_STACK_OVERFLOW 2 +#endif +#define configRECORD_STACK_HIGH_ADDRESS 1 // This must be set as the port requires TCB.pxEndOfStack + +// ------------------- Run-time Stats ---------------------- + +#ifdef CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS +#define configGENERATE_RUN_TIME_STATS 1 /* Used by vTaskGetRunTimeStats() */ +#endif +#ifdef CONFIG_FREERTOS_USE_TRACE_FACILITY +#define configUSE_TRACE_FACILITY 1 /* Used by uxTaskGetSystemState(), and other trace facility functions */ +#endif +#ifdef CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS +#define configUSE_STATS_FORMATTING_FUNCTIONS 1 /* Used by vTaskList() */ +#endif + +// -------------------- Co-routines ----------------------- + +#define configUSE_CO_ROUTINES 0 +#define configMAX_CO_ROUTINE_PRIORITIES 2 + +// ------------------- Software Timer ---------------------- + +#define configUSE_TIMERS 1 +#define configTIMER_TASK_PRIORITY CONFIG_FREERTOS_TIMER_TASK_PRIORITY +#define configTIMER_QUEUE_LENGTH CONFIG_FREERTOS_TIMER_QUEUE_LENGTH +#define configTIMER_TASK_STACK_DEPTH CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH + +// -------------------- API Includes ----------------------- + +#define configENABLE_BACKWARD_COMPATIBILITY 0 + +#define INCLUDE_vTaskPrioritySet 1 +#define INCLUDE_uxTaskPriorityGet 1 +#define INCLUDE_vTaskDelete 1 +#define INCLUDE_vTaskSuspend 1 +#define INCLUDE_xTaskDelayUntil 1 +#define INCLUDE_vTaskDelay 1 +#define INCLUDE_xTaskGetIdleTaskHandle 1 +#define INCLUDE_xTaskAbortDelay 1 +#define INCLUDE_xSemaphoreGetMutexHolder 1 +#define INCLUDE_xTaskGetHandle 1 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 +#define INCLUDE_uxTaskGetStackHighWaterMark2 0 +#define INCLUDE_eTaskGetState 1 +#define INCLUDE_xTaskResumeFromISR 1 +#define INCLUDE_xTimerPendFunctionCall 1 +#define INCLUDE_xTaskGetSchedulerState 1 +#define INCLUDE_xTaskGetCurrentTaskHandle 1 + +// -------------------- Trace Macros ----------------------- + +/* +For trace macros. +Note: Include trace macros here and not above as trace macros are dependent on some of the FreeRTOS configs +*/ +#ifndef __ASSEMBLER__ +#if CONFIG_SYSVIEW_ENABLE +#include "SEGGER_SYSVIEW_FreeRTOS.h" +#undef INLINE // to avoid redefinition +#endif //CONFIG_SYSVIEW_ENABLE +#endif /* def __ASSEMBLER__ */ + +/* +Default values for trace macros added by ESP-IDF and are not part of Vanilla FreeRTOS +*/ +#ifndef traceISR_EXIT + #define traceISR_EXIT() +#endif +#ifndef traceISR_ENTER + #define traceISR_ENTER(_n_) +#endif + +/* ------------------------------------------------ IDF Compatibility -------------------------------------------------- + * - We need these in order for ESP-IDF to compile + * ------------------------------------------------------------------------------------------------------------------ */ + +#define portNUM_PROCESSORS configNUM_CORES +#ifdef CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID +#define configTASKLIST_INCLUDE_COREID 1 +#endif + +#ifndef __ASSEMBLER__ +#if CONFIG_APPTRACE_SV_ENABLE +extern uint32_t port_switch_flag[]; +#define os_task_switch_is_pended(_cpu_) (port_switch_flag[_cpu_]) +#else +#define os_task_switch_is_pended(_cpu_) (false) +#endif +#endif + +// ---------------------- Features ------------------------- + +/* These currently aren't required, but could be useful additions in the future */ +#if 0 +#ifndef configIDLE_TASK_STACK_SIZE +#define configIDLE_TASK_STACK_SIZE CONFIG_FREERTOS_IDLE_TASK_STACKSIZE +#endif +#if CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER +#define configCHECK_MUTEX_GIVEN_BY_OWNER 1 +#else +#define configCHECK_MUTEX_GIVEN_BY_OWNER 0 +#endif +#endif //0 + +// -------------------- Compatibility ---------------------- + +// backward compatibility for 4.4 +#define xTaskRemoveFromUnorderedEventList vTaskRemoveFromUnorderedEventList + +#endif /* FREERTOS_CONFIG_SMP_H */ diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/include/freertos/portmacro.h b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/include/freertos/portmacro.h new file mode 100644 index 0000000000..736c6da5f3 --- /dev/null +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/include/freertos/portmacro.h @@ -0,0 +1,652 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#pragma once + +#include "sdkconfig.h" +#include +#include "spinlock.h" +#include "soc/interrupt_core0_reg.h" +#include "esp_macros.h" +#include "hal/cpu_hal.h" +#include "esp_private/crosscore_int.h" + +#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 first as they are used further down in this file + * ------------------------------------------------------------------------------------------------------------------ */ + +#define portCHAR uint8_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 ) + +//TODO: Check this +// interrupt module will mask interrupt with priority less than threshold +#define RVHAL_EXCM_LEVEL 4 +// TODO: Check this end + + +/* ----------------------------------------------- Port Configurations ------------------------------------------------- + * - Configurations values supplied by each port + * - Required by FreeRTOS + * ------------------------------------------------------------------------------------------------------------------ */ + +#define portCRITICAL_NESTING_IN_TCB 1 +#define portSTACK_GROWTH ( -1 ) +#define portTICK_PERIOD_MS ( ( TickType_t ) ( 1000 / configTICK_RATE_HZ ) ) +#define portBYTE_ALIGNMENT 16 +#define portNOP() __asm volatile (" 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 + * ------------------------------------------------------------------------------------------------------------------ */ + +/* ---------------------- Spinlocks ------------------------ + - Spinlocks added to match API with SMP FreeRTOS. Single core RISC-V does not need spin locks + - Because single core does not have a primitive spinlock data type, we have to implement one here + * @note [refactor-todo] Refactor critical section API so that this is no longer required + * ------------------------------------------------------ */ + +/** + * @brief Spinlock object + * Owner: + * - Set to 0 if uninitialized + * - Set to portMUX_FREE_VAL when free + * - Set to CORE_ID_REGVAL_PRO or CORE_ID_REGVAL_AP when locked + * - Any other value indicates corruption + * Count: + * - 0 if unlocked + * - Recursive count if locked + * + * @note Not a true spinlock as single core RISC-V does not have atomic compare and set instruction + * @note Keep portMUX_INITIALIZER_UNLOCKED in sync with this struct + */ +//typedef struct { +// uint32_t owner; +// uint32_t count; +//} portMUX_TYPE; +typedef spinlock_t portMUX_TYPE; /**< Spinlock type used by FreeRTOS critical sections */ +#if 0 +#define portMUX_INITIALIZER_UNLOCKED { \ + .owner = portMUX_FREE_VAL, \ + .count = 0, \ + } +#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) ({ \ + (mux)->owner = portMUX_FREE_VAL; \ + (mux)->count = 0; \ +}) +#endif +#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 */ + + +// ----------------------- Memory -------------------------- + +// --------------------- Interrupts ------------------------ + +BaseType_t xPortCheckIfInISR(void); + +// TODO: Check this +#if 0 +/** + * @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); +#endif +// TODO: Check this end + +// TODO: Check this +/** + * @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); +// TODO: Check this end + +// TODO: Check this +/* ---------------------- Spinlocks ------------------------*/ +/** + * @brief Wrapper for atomic compare-and-set instruction + * + * @note Isn't a real atomic CAS. + * @note [refactor-todo] check if we still need this + * @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 + * + * @note Isn't a real atomic CAS. + * @note [refactor-todo] check if we still need this + * @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 uxPortCompareSetExtram(volatile uint32_t *addr, uint32_t compare, uint32_t *set); +// TODO: Check this end + +// ------------------ Critical Sections -------------------- + +UBaseType_t uxPortEnterCriticalFromISR( void ); +void vPortExitCriticalFromISR( UBaseType_t level ); + +/* +These are always called with interrupts already disabled. We simply need to get/release the spinlocks +*/ + +extern portMUX_TYPE port_xTaskLock; +extern portMUX_TYPE port_xISRLock; + +void vPortTakeLock( portMUX_TYPE *lock ); +void vPortReleaseLock( portMUX_TYPE *lock ); + +/** + * @brief Enter a critical section + * + * - Simply disable interrupts + * - Can be nested + */ +void vPortEnterCritical(void); + +/** + * @brief Exit a critical section + * + * - Reenables interrupts + * - Can be nested + */ +void vPortExitCritical(void); + +// ---------------------- Yielding ------------------------- + +void vPortYield( void ); +static inline void __attribute__((always_inline)) vPortYieldCore( BaseType_t xCoreID ); +// TODO: Check this +//static inline void __attribute__((always_inline)) vPortYieldFromISR( void ); +// TODO: Check this end + +/** + * @brief Set interrupt mask and return current interrupt enable register + * + * @note [refactor-todo] Check if this function should be renamed (due to int return type) + * @return int Current interrupt enable register before set + */ +int vPortSetInterruptMask(void); + +/** + * @brief Clear current interrupt mask and set given mask + * + * @param mask Interrupt mask + */ +void vPortClearInterruptMask(int mask); + +// TODO: Check this +#if 0 +/** + * @brief Perform a context switch from a task + * + * @note [refactor-todo] The rest of ESP-IDF should call taskYield() instead + */ +void vPortYield(void); +#endif +// TODO: Check this end + +/** + * @brief Perform a context switch from an ISR + */ +void vPortYieldFromISR(void); + +#define portYIELD_FROM_ISR_CHECK(x) ({ \ + if ( (x) == pdTRUE ) { \ + vPortYieldFromISR(); \ + } \ +}) +#define portYIELD_FROM_ISR_NO_CHECK() vPortYieldFromISR() + +// TODO: Check this +#if 0 +/** + * @brief Yields the other core + * + * @note Added to be compatible with SMP API + * @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 + * @note [refactor-todo] Check if this function should be renamed (due to bool return type) + * @return true Core can yield + * @return false Core cannot yield + */ +static inline bool xPortCanYield(void); +#endif +// TODO: Check this end + +// ----------------------- System -------------------------- + +static inline BaseType_t __attribute__((always_inline)) xPortGetCoreID( void ); + +// ----------------------- TCB Cleanup -------------------------- + +void vPortCleanUpTCB ( void *pxTCB ); + +// TODO: Check this +#if 0 +// ------------------- 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); +#endif +// TODO: Check this end + +// TODO: Check this +#if 0 +// ----------------------- System -------------------------- + +/** + * @brief Get the tick rate per second + * + * @note [refactor-todo] make this inline + * @note [refactor-todo] Check if this function should be renamed (due to uint return type) + * @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 Added to be compatible with SMP API + * @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) +{ + return (BaseType_t) cpu_hal_get_core_id(); +} +#endif +// TODO: Check this end + + + +/* ------------------------------------------- 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 -------------------------- + +// TODO: Check this +#if 0 +/** + * @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) pvPortMalloc(size) +#define pvPortMallocStackMem(size) pvPortMalloc(size) +#endif +// TODO: Check this end + +// --------------------- Interrupts ------------------------ + +#define portDISABLE_INTERRUPTS() vPortSetInterruptMask() +#define portENABLE_INTERRUPTS() vPortClearInterruptMask(1) +#define portRESTORE_INTERRUPTS(x) vPortClearInterruptMask(x) + +#define portSET_INTERRUPT_MASK_FROM_ISR() ({ \ + unsigned int cur_level; \ + cur_level = REG_READ(INTERRUPT_CORE0_CPU_INT_THRESH_REG); \ + vTaskEnterCritical(); \ + cur_level; \ +}) +#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) ({ \ + vTaskExitCritical(); \ + portRESTORE_INTERRUPTS(x); \ +}) + +// ------------------ Critical Sections -------------------- + +#define portGET_TASK_LOCK() vPortTakeLock(&port_xTaskLock) +#define portRELEASE_TASK_LOCK() vPortReleaseLock(&port_xTaskLock) +#define portGET_ISR_LOCK() vPortTakeLock(&port_xISRLock) +#define portRELEASE_ISR_LOCK() vPortReleaseLock(&port_xISRLock) + +#define portENTER_CRITICAL_IDF(mux) {(void)mux; vPortEnterCritical();} +#define portEXIT_CRITICAL_IDF(mux) {(void)mux; vPortExitCritical();} + +//Critical sections used by FreeRTOS SMP +extern void vTaskEnterCritical( void ); +extern void vTaskExitCritical( void ); +#define portENTER_CRITICAL_SMP() vTaskEnterCritical(); +#define portEXIT_CRITICAL_SMP() vTaskExitCritical(); + +#if defined(__cplusplus) && (__cplusplus > 201703L) +#define portENTER_CRITICAL(...) CHOOSE_MACRO_VA_ARG(portENTER_CRITICAL_IDF, portENTER_CRITICAL_SMP __VA_OPT__(,) __VA_ARGS__)(__VA_ARGS__) +#define portEXIT_CRITICAL(...) CHOOSE_MACRO_VA_ARG(portEXIT_CRITICAL_IDF, portEXIT_CRITICAL_SMP __VA_OPT__(,) __VA_ARGS__)(__VA_ARGS__) +#else +#define portENTER_CRITICAL(...) CHOOSE_MACRO_VA_ARG(portENTER_CRITICAL_IDF, portENTER_CRITICAL_SMP, ##__VA_ARGS__)(__VA_ARGS__) +#define portEXIT_CRITICAL(...) CHOOSE_MACRO_VA_ARG(portEXIT_CRITICAL_IDF, portEXIT_CRITICAL_SMP, ##__VA_ARGS__)(__VA_ARGS__) +#endif + +#define portTRY_ENTER_CRITICAL(mux, timeout) ({ \ + (void)mux; (void)timeout; \ + vPortEnterCritical(); \ + BaseType_t ret = pdPASS; \ + ret; \ +}) +//In single-core RISC-V, we can use the same critical section API +#define portENTER_CRITICAL_ISR(mux) portENTER_CRITICAL(mux) +#define portEXIT_CRITICAL_ISR(mux) portEXIT_CRITICAL(mux) +#define portTRY_ENTER_CRITICAL_ISR(mux, timeout) portTRY_ENTER_CRITICAL(mux, timeout) + +/* [refactor-todo] on RISC-V, both ISR and non-ISR cases result in the same call. We can redefine this macro */ +#define portENTER_CRITICAL_SAFE(mux) ({ \ + if (xPortInIsrContext()) { \ + portENTER_CRITICAL_ISR(mux); \ + } else { \ + portENTER_CRITICAL(mux); \ + } \ +}) +#define portEXIT_CRITICAL_SAFE(mux) ({ \ + if (xPortInIsrContext()) { \ + portEXIT_CRITICAL_ISR(mux); \ + } else { \ + portEXIT_CRITICAL(mux); \ + } \ +}) +#define portTRY_ENTER_CRITICAL_SAFE(mux, timeout) portENTER_CRITICAL_SAFE(mux, timeout) + +// ---------------------- Yielding ------------------------- + +#define portYIELD() vPortYield() +#if defined(__cplusplus) && (__cplusplus > 201703L) +#define portYIELD_FROM_ISR(...) CHOOSE_MACRO_VA_ARG(portYIELD_FROM_ISR_CHECK, portYIELD_FROM_ISR_NO_CHECK __VA_OPT__(,) __VA_ARGS__)(__VA_ARGS__) +#else +#define portYIELD_FROM_ISR(...) CHOOSE_MACRO_VA_ARG(portYIELD_FROM_ISR_CHECK, portYIELD_FROM_ISR_NO_CHECK, ##__VA_ARGS__)(__VA_ARGS__) +#endif +#define portYIELD_CORE(x) vPortYieldCore(x) + +// TODO: Check this +#if 0 +#define portYIELD_FROM_ISR_NO_ARG() vPortYieldFromISR() +#define portYIELD_FROM_ISR_ARG(xHigherPriorityTaskWoken) ({ \ + if (xHigherPriorityTaskWoken == pdTRUE) { \ + vPortYieldFromISR(); \ + } \ +}) +/** + * @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(portYIELD_FROM_ISR_ARG, portYIELD_FROM_ISR_NO_ARG __VA_OPT__(,) __VA_ARGS__)(__VA_ARGS__) +#else +#define portYIELD_FROM_ISR(...) CHOOSE_MACRO_VA_ARG(portYIELD_FROM_ISR_ARG, portYIELD_FROM_ISR_NO_ARG, ##__VA_ARGS__)(__VA_ARGS__) +#endif + + +#define portEND_SWITCHING_ISR(xSwitchRequired) if(xSwitchRequired) vPortYield() +/* 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() portYIELD() +#endif +// TODO: Check this end + +// +// ----------------------- System -------------------------- + +#define portGET_CORE_ID() xPortGetCoreID() +#define portCHECK_IF_IN_ISR() xPortCheckIfInISR() + +// TODO: Check this +#if 0 +// ------------------- Hook Functions ---------------------- + +#define portSUPPRESS_TICKS_AND_SLEEP(idleTime) vApplicationSleep(idleTime) +#endif +// TODO: Check this end + +// ------------------- Run Time Stats ---------------------- + +#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() +#define portGET_RUN_TIME_COUNTER_VALUE() 0 +#ifdef CONFIG_FREERTOS_RUN_TIME_STATS_USING_ESP_TIMER +/* Coarse resolution time (us) */ +#define portALT_GET_RUN_TIME_COUNTER_VALUE(x) do {x = (uint32_t)esp_timer_get_time();} while(0) +#endif + +// ------------------- TCB Cleanup ---------------------- + +#define portCLEAN_UP_TCB( pxTCB ) vPortCleanUpTCB( pxTCB ) + +/* --------------------------------------------- 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, port_common.c, or other assembly files + * ------------------------------------------------------------------------------------------------------------------ */ + +// --------------------- Interrupts ------------------------ + +// ------------------ Critical Sections -------------------- + +// ---------------------- Yielding ------------------------- + +static inline void __attribute__((always_inline)) vPortYieldCore( BaseType_t xCoreID ) +{ + esp_crosscore_int_send_yield( xCoreID ); +} + +// TODO: Check this +#if 0 +static inline bool IRAM_ATTR xPortCanYield(void) +{ + uint32_t threshold = REG_READ(INTERRUPT_CORE0_CPU_INT_THRESH_REG); + /* when enter critical code, FreeRTOS will mask threshold to RVHAL_EXCM_LEVEL + * and exit critical code, will recover threshold value (1). so threshold <= 1 + * means not in critical code + */ + return (threshold <= 1); +} +#endif +// TODO: Check this end + +// ----------------------- System -------------------------- + +static inline BaseType_t __attribute__((always_inline)) xPortGetCoreID( void ) +{ + return (BaseType_t) cpu_hal_get_core_id(); +} + +/* ------------------------------------------------ IDF Compatibility -------------------------------------------------- + * - These macros and functions need to be defined for IDF to compile + * ------------------------------------------------------------------------------------------------------------------ */ + +// --------------------- Interrupts ------------------------ + +static inline BaseType_t xPortInIsrContext(void) +{ + //Just call the FreeRTOS port interface version + return xPortCheckIfInISR(); +} + +// ---------------------- Spinlocks ------------------------ + +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 uxPortCompareSetExtram(volatile uint32_t *addr, uint32_t compare, uint32_t *set) +{ +#if defined(CONFIG_SPIRAM) + compare_and_set_extram(addr, compare, set); +#endif +} + +// ------------------ Critical Sections -------------------- + +// ---------------------- Yielding ------------------------- + +static inline bool IRAM_ATTR xPortCanYield(void) +{ + uint32_t threshold = REG_READ(INTERRUPT_CORE0_CPU_INT_THRESH_REG); + /* when enter critical code, FreeRTOS will mask threshold to RVHAL_EXCM_LEVEL + * and exit critical code, will recover threshold value (1). so threshold <= 1 + * means not in critical code + */ + return (threshold <= 1); +} + +// ----------------------- System -------------------------- + +void vPortSetStackWatchpoint(void *pxStackStart); + +#define portVALID_TCB_MEM(ptr) (esp_ptr_internal(ptr) && esp_ptr_byte_accessible(ptr)) +#ifdef CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY +#define portVALID_STACK_MEM(ptr) (esp_ptr_byte_accessible(ptr)) +#else +#define portVALID_STACK_MEM(ptr) (esp_ptr_internal(ptr) && esp_ptr_byte_accessible(ptr)) +#endif + +#define portTcbMemoryCaps (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT) +#define portStackMemoryCaps (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT) + +/* ------------------------------------------------------ Misc --------------------------------------------------------- + * - Miscellaneous porting macros + * - These are not port of the FreeRTOS porting interface, but are used by other FreeRTOS dependent components + * ------------------------------------------------------------------------------------------------------------------ */ + +// --------------------- App-Trace ------------------------- + +#if CONFIG_APPTRACE_SV_ENABLE +extern int xPortSwitchFlag; +#define os_task_switch_is_pended(_cpu_) (xPortSwitchFlag) +#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 + +// --------------- Compatibility Includes ------------------ +/* +ESP-IDF currently does not have a "Include what you use" policy. A lot of files implicitly pull in API through +portmacro.h. Therefore, we need to keep these headers around for now to allow the rest of IDF to compile. + +[refactor-todo] Clean up ESP-IDF inclusion dependencies and add a inclusion check. +*/ + +#include +#include +#include +#include "esp_attr.h" +#include "esp_newlib.h" +#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 */ + +/* [refactor-todo] These includes are not directly used in this file. They are kept into to prevent a breaking change. Remove these. */ +#include + +/* [refactor-todo] introduce a port wrapper function to avoid including esp_timer.h into the public header */ +#if CONFIG_FREERTOS_RUN_TIME_STATS_USING_ESP_TIMER +#include "esp_timer.h" +#endif + +#ifdef __cplusplus +} +#endif diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c new file mode 100644 index 0000000000..eb340b065b --- /dev/null +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c @@ -0,0 +1,729 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sdkconfig.h" +#include +#include "soc/soc_caps.h" +#include "soc/periph_defs.h" +#include "soc/system_reg.h" +#include "hal/systimer_hal.h" +#include "hal/systimer_ll.h" +#include "riscv/rvruntime-frames.h" +#include "riscv/riscv_interrupts.h" +#include "riscv/interrupt.h" +#include "esp_private/crosscore_int.h" +#include "esp_attr.h" +#include "esp_system.h" +#include "esp_heap_caps_init.h" +#include "esp_private/esp_int_wdt.h" +#include "esp_task_wdt.h" +#include "esp_task.h" +#include "esp_intr_alloc.h" +#include "esp_log.h" +#include "FreeRTOS.h" /* This pulls in portmacro.h */ +#include "task.h" +#include "portmacro.h" + +#ifdef CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER +#include "soc/periph_defs.h" +#include "soc/system_reg.h" +#include "hal/systimer_hal.h" +#include "hal/systimer_ll.h" +#endif + +#ifdef CONFIG_PM_TRACE +#include "esp_private/pm_trace.h" +#endif //CONFIG_PM_TRACE + + +/* ---------------------------------------------------- Variables ------------------------------------------------------ + * + * ------------------------------------------------------------------------------------------------------------------ */ + +static const char *TAG = "cpu_start"; // [refactor-todo]: might be appropriate to change in the future, but + +/** + * @brief A variable is used to keep track of the critical section nesting. + * @note This variable has to be stored as part of the task context and must be initialized to a non zero value + * to ensure interrupts don't inadvertently become unmasked before the scheduler starts. + * As it is stored as part of the task context it will automatically be set to 0 when the first task is started. + */ +static UBaseType_t uxCriticalNesting = 0; +static UBaseType_t uxSavedInterruptState = 0; +BaseType_t uxSchedulerRunning = 0; +UBaseType_t uxInterruptNesting = 0; +BaseType_t xPortSwitchFlag = 0; +__attribute__((aligned(16))) static StackType_t xIsrStack[configISR_STACK_SIZE]; +StackType_t *xIsrStackTop = &xIsrStack[0] + (configISR_STACK_SIZE & (~((portPOINTER_SIZE_TYPE)portBYTE_ALIGNMENT_MASK))); +portMUX_TYPE port_xTaskLock = portMUX_INITIALIZER_UNLOCKED; +portMUX_TYPE port_xISRLock = portMUX_INITIALIZER_UNLOCKED; + +/* ------------------------------------------------ IDF Compatibility -------------------------------------------------- + * - These need to be defined for IDF to compile + * ------------------------------------------------------------------------------------------------------------------ */ + +// --------------------- Interrupts ------------------------ + +BaseType_t IRAM_ATTR xPortInterruptedFromISRContext(void) +{ + /* For single core, this can be the same as xPortCheckIfInISR() because reading it is atomic */ + return uxInterruptNesting; +} + +// ------------------ Critical Sections -------------------- + +// ----------------------- System -------------------------- + +// TODO: Check this +#if 0 +uint32_t xPortGetTickRateHz(void) +{ + return (uint32_t)configTICK_RATE_HZ; +} +#endif +// TODO: Check this end + +#define STACK_WATCH_AREA_SIZE 32 +#define STACK_WATCH_POINT_NUMBER (SOC_CPU_WATCHPOINTS_NUM - 1) + +void vPortSetStackWatchpoint(void *pxStackStart) +{ + uint32_t addr = (uint32_t)pxStackStart; + addr = (addr + (STACK_WATCH_AREA_SIZE - 1)) & (~(STACK_WATCH_AREA_SIZE - 1)); + esp_cpu_set_watchpoint(STACK_WATCH_POINT_NUMBER, (char *)addr, STACK_WATCH_AREA_SIZE, ESP_CPU_WATCHPOINT_STORE); +} + +// ---------------------- Tick Timer ----------------------- + +BaseType_t xPortSysTickHandler(void); + +#if CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER + +_Static_assert(SOC_CPU_CORES_NUM <= SOC_SYSTIMER_ALARM_NUM - 1, "the number of cores must match the number of core alarms in SYSTIMER"); + +void SysTickIsrHandler(void *arg); + +static uint32_t s_handled_systicks[portNUM_PROCESSORS] = { 0 }; + +#define SYSTICK_INTR_ID (ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE) + +/** + * @brief Set up the systimer peripheral to generate the tick interrupt + * + * Both timer alarms are configured in periodic mode. + * It is done at the same time so SysTicks for both CPUs occur at the same time or very close. + * Shifts a time of triggering interrupts for core 0 and core 1. + */ +void vPortSetupTimer(void) +{ + unsigned cpuid = xPortGetCoreID(); +#ifdef CONFIG_FREERTOS_CORETIMER_SYSTIMER_LVL3 + const unsigned level = ESP_INTR_FLAG_LEVEL3; +#else + const unsigned level = ESP_INTR_FLAG_LEVEL1; +#endif + /* Systimer HAL layer object */ + static systimer_hal_context_t systimer_hal; + /* set system timer interrupt vector */ + ESP_ERROR_CHECK(esp_intr_alloc(ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE + cpuid, ESP_INTR_FLAG_IRAM | level, SysTickIsrHandler, &systimer_hal, NULL)); + + if (cpuid == 0) { + systimer_hal_init(&systimer_hal); + systimer_ll_set_counter_value(systimer_hal.dev, SYSTIMER_LL_COUNTER_OS_TICK, 0); + systimer_ll_apply_counter_value(systimer_hal.dev, SYSTIMER_LL_COUNTER_OS_TICK); + + for (cpuid = 0; cpuid < SOC_CPU_CORES_NUM; cpuid++) { + systimer_hal_counter_can_stall_by_cpu(&systimer_hal, SYSTIMER_LL_COUNTER_OS_TICK, cpuid, false); + } + + for (cpuid = 0; cpuid < portNUM_PROCESSORS; ++cpuid) { + uint32_t alarm_id = SYSTIMER_LL_ALARM_OS_TICK_CORE0 + cpuid; + + /* configure the timer */ + systimer_hal_connect_alarm_counter(&systimer_hal, alarm_id, SYSTIMER_LL_COUNTER_OS_TICK); + systimer_hal_set_alarm_period(&systimer_hal, alarm_id, 1000000UL / CONFIG_FREERTOS_HZ); + systimer_hal_select_alarm_mode(&systimer_hal, alarm_id, SYSTIMER_ALARM_MODE_PERIOD); + systimer_hal_counter_can_stall_by_cpu(&systimer_hal, SYSTIMER_LL_COUNTER_OS_TICK, cpuid, true); + if (cpuid == 0) { + systimer_hal_enable_alarm_int(&systimer_hal, alarm_id); + systimer_hal_enable_counter(&systimer_hal, SYSTIMER_LL_COUNTER_OS_TICK); +#ifndef CONFIG_FREERTOS_UNICORE + // SysTick of core 0 and core 1 are shifted by half of period + systimer_hal_counter_value_advance(&systimer_hal, SYSTIMER_LL_COUNTER_OS_TICK, 1000000UL / CONFIG_FREERTOS_HZ / 2); +#endif + } + } + } else { + uint32_t alarm_id = SYSTIMER_LL_ALARM_OS_TICK_CORE0 + cpuid; + systimer_hal_enable_alarm_int(&systimer_hal, alarm_id); + } +} + +/** + * @brief Systimer interrupt handler. + * + * The Systimer interrupt for SysTick works in periodic mode no need to calc the next alarm. + * If a timer interrupt is ever serviced more than one tick late, it is necessary to process multiple ticks. + */ +IRAM_ATTR void SysTickIsrHandler(void *arg) +{ + uint32_t cpuid = xPortGetCoreID(); + systimer_hal_context_t *systimer_hal = (systimer_hal_context_t *)arg; +#ifdef CONFIG_PM_TRACE + ESP_PM_TRACE_ENTER(TICK, cpuid); +#endif + + uint32_t alarm_id = SYSTIMER_LL_ALARM_OS_TICK_CORE0 + cpuid; + do { + systimer_ll_clear_alarm_int(systimer_hal->dev, alarm_id); + + uint32_t diff = systimer_hal_get_counter_value(systimer_hal, SYSTIMER_LL_COUNTER_OS_TICK) / systimer_ll_get_alarm_period(systimer_hal->dev, alarm_id) - s_handled_systicks[cpuid]; + if (diff > 0) { + if (s_handled_systicks[cpuid] == 0) { + s_handled_systicks[cpuid] = diff; + diff = 1; + } else { + s_handled_systicks[cpuid] += diff; + } + + do { + xPortSysTickHandler(); + } while (--diff); + } + } while (systimer_ll_is_alarm_int_fired(systimer_hal->dev, alarm_id)); + +#ifdef CONFIG_PM_TRACE + ESP_PM_TRACE_EXIT(TICK, cpuid); +#endif +} + +#endif // CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER + +// --------------------- App Start-up ---------------------- + +extern void app_main(void); + +static void main_task(void* args) +{ +#if !CONFIG_FREERTOS_UNICORE + // Wait for FreeRTOS initialization to finish on APP CPU, before replacing its startup stack + while (uxSchedulerRunning == 0) { + ; + } +#endif + + // [refactor-todo] check if there is a way to move the following block to esp_system startup + heap_caps_enable_nonos_stack_heaps(); + + // Now we have startup stack RAM available for heap, enable any DMA pool memory +#if CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL + if (g_spiram_ok) { + esp_err_t r = esp_spiram_reserve_dma_pool(CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL); + if (r != ESP_OK) { + ESP_EARLY_LOGE(TAG, "Could not reserve internal/DMA pool (error 0x%x)", r); + abort(); + } + } +#endif + + //Initialize task wdt if configured to do so +#if CONFIG_ESP_TASK_WDT + esp_task_wdt_config_t twdt_config = { + .timeout_ms = CONFIG_ESP_TASK_WDT_TIMEOUT_S * 1000, + .idle_core_mask = 0, +#if CONFIG_ESP_TASK_WDT_PANIC + .trigger_panic = true, +#endif + }; +#if CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 + twdt_config.idle_core_mask |= (1 << 0); +#endif +#if CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1 + twdt_config.idle_core_mask |= (1 << 1); +#endif + ESP_ERROR_CHECK(esp_task_wdt_init(&twdt_config)); +#endif // CONFIG_ESP_TASK_WDT + + app_main(); + vTaskDelete(NULL); +} + +void esp_startup_start_app_common(void) +{ +#if CONFIG_ESP_INT_WDT + esp_int_wdt_init(); + //Initialize the interrupt watch dog for CPU0. + esp_int_wdt_cpu_init(); +#endif + + esp_crosscore_int_init(); + +#ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME + esp_gdbstub_init(); +#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME + + portBASE_TYPE res = xTaskCreatePinnedToCore(main_task, "main", + ESP_TASK_MAIN_STACK, NULL, + ESP_TASK_MAIN_PRIO, NULL, ESP_TASK_MAIN_CORE); + assert(res == pdTRUE); + (void)res; +} + +void esp_startup_start_app(void) +{ + esp_startup_start_app_common(); + + ESP_LOGI(TAG, "Starting scheduler."); + vTaskStartScheduler(); +} + +/* ---------------------------------------------- Port Implementations ------------------------------------------------- + * Implementations of Porting Interface functions + * ------------------------------------------------------------------------------------------------------------------ */ + +// --------------------- Interrupts ------------------------ + +BaseType_t xPortCheckIfInISR(void) +{ + return uxInterruptNesting; +} + +// ------------------ Critical Sections -------------------- + +void vPortTakeLock( portMUX_TYPE *lock ) +{ + spinlock_acquire( lock, portMUX_NO_TIMEOUT); +} + +void vPortReleaseLock( portMUX_TYPE *lock ) +{ + spinlock_release( lock ); +} + +// ---------------------- Yielding ------------------------- + +// ----------------------- System -------------------------- + +/* ------------------------------------------------ FreeRTOS Portable -------------------------------------------------- + * - Provides implementation for functions required by FreeRTOS + * - Declared in portable.h + * ------------------------------------------------------------------------------------------------------------------ */ + +// ----------------- Scheduler Start/End ------------------- + +extern void esprv_intc_int_set_threshold(int); // FIXME, this function is in ROM only +BaseType_t xPortStartScheduler(void) +{ + uxInterruptNesting = 0; + uxCriticalNesting = 0; + uxSchedulerRunning = 0; + + /* Setup the hardware to generate the tick. */ + vPortSetupTimer(); + + esprv_intc_int_set_threshold(1); /* set global INTC masking level */ + riscv_global_interrupts_enable(); + + vPortYield(); + + /*Should not get here*/ + return pdFALSE; +} + +void vPortEndScheduler(void) +{ + /* very unlikely this function will be called, so just trap here */ + abort(); +} + +// ----------------------- Memory -------------------------- + +#define FREERTOS_SMP_MALLOC_CAPS (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT) + +void *pvPortMalloc( size_t xSize ) +{ + return heap_caps_malloc(xSize, FREERTOS_SMP_MALLOC_CAPS); +} + +void vPortFree( void * pv ) +{ + heap_caps_free(pv); +} + +void vPortInitialiseBlocks( void ) +{ + ; //Does nothing, heap is initialized separately in ESP-IDF +} + +size_t xPortGetFreeHeapSize( void ) +{ + return esp_get_free_heap_size(); +} + +#if( configSTACK_ALLOCATION_FROM_SEPARATE_HEAP == 1 ) +void *pvPortMallocStack( size_t xSize ) +{ + return NULL; +} + +void vPortFreeStack( void *pv ) +{ + +} +#endif + +#if ( configSUPPORT_STATIC_ALLOCATION == 1 ) +void vApplicationGetIdleTaskMemory(StaticTask_t **ppxIdleTaskTCBBuffer, + StackType_t **ppxIdleTaskStackBuffer, + uint32_t *pulIdleTaskStackSize ) +{ + StaticTask_t *pxTCBBufferTemp; + StackType_t *pxStackBufferTemp; + //Allocate TCB and stack buffer in internal memory + pxTCBBufferTemp = pvPortMalloc(sizeof(StaticTask_t)); + pxStackBufferTemp = pvPortMalloc(CONFIG_FREERTOS_IDLE_TASK_STACKSIZE); + assert(pxTCBBufferTemp != NULL); + assert(pxStackBufferTemp != NULL); + //Write back pointers + *ppxIdleTaskTCBBuffer = pxTCBBufferTemp; + *ppxIdleTaskStackBuffer = pxStackBufferTemp; + *pulIdleTaskStackSize = CONFIG_FREERTOS_IDLE_TASK_STACKSIZE; +} + +void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, + StackType_t **ppxTimerTaskStackBuffer, + uint32_t *pulTimerTaskStackSize ) +{ + StaticTask_t *pxTCBBufferTemp; + StackType_t *pxStackBufferTemp; + //Allocate TCB and stack buffer in internal memory + pxTCBBufferTemp = pvPortMalloc(sizeof(StaticTask_t)); + pxStackBufferTemp = pvPortMalloc(configTIMER_TASK_STACK_DEPTH); + assert(pxTCBBufferTemp != NULL); + assert(pxStackBufferTemp != NULL); + //Write back pointers + *ppxTimerTaskTCBBuffer = pxTCBBufferTemp; + *ppxTimerTaskStackBuffer = pxStackBufferTemp; + *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; +} +#endif //( configSUPPORT_STATIC_ALLOCATION == 1 ) + +// ------------------------ Stack -------------------------- + +__attribute__((noreturn)) static void _prvTaskExitError(void) +{ + /* A function that implements a task must not exit or attempt to return to + its caller as there is nothing to return to. If a task wants to exit it + should instead call vTaskDelete( NULL ). + + Artificially force an assert() to be triggered if configASSERT() is + defined, then stop here so application writers can catch the error. */ + configASSERT(uxCriticalNesting == ~0UL); + portDISABLE_INTERRUPTS(); + abort(); +} + +__attribute__((naked)) static void prvTaskExitError(void) +{ + asm volatile(".option push\n" \ + ".option norvc\n" \ + "nop\n" \ + ".option pop"); + /* Task entry's RA will point here. Shifting RA into prvTaskExitError is necessary + to make GDB backtrace ending inside that function. + Otherwise backtrace will end in the function laying just before prvTaskExitError in address space. */ + _prvTaskExitError(); +} + +StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters) +{ + extern uint32_t __global_pointer$; + uint8_t *task_thread_local_start; + uint8_t *threadptr; + extern char _thread_local_start, _thread_local_end, _flash_rodata_start; + + /* Byte pointer, so that subsequent calculations don't depend on sizeof(StackType_t). */ + uint8_t *sp = (uint8_t *) pxTopOfStack; + + /* Set up TLS area. + * The following diagram illustrates the layout of link-time and run-time + * TLS sections. + * + * +-------------+ + * |Section: | Linker symbols: + * |.flash.rodata| --------------- + * 0x0+-------------+ <-- _flash_rodata_start + * ^ | | + * | | Other data | + * | | ... | + * | +-------------+ <-- _thread_local_start + * | |.tbss | ^ + * v | | | + * 0xNNNN|int example; | | (thread_local_size) + * |.tdata | v + * +-------------+ <-- _thread_local_end + * | Other data | + * | ... | + * | | + * +-------------+ + * + * Local variables of + * pxPortInitialiseStack + * ----------------------- + * +-------------+ <-- pxTopOfStack + * |.tdata (*) | ^ + * ^ |int example; | |(thread_local_size + * | | | | + * | |.tbss (*) | v + * | +-------------+ <-- task_thread_local_start + * 0xNNNN | | | ^ + * | | | | + * | | | |_thread_local_start - _rodata_start + * | | | | + * | | | v + * v +-------------+ <-- threadptr + * + * (*) The stack grows downward! + */ + + uint32_t thread_local_sz = (uint32_t) (&_thread_local_end - &_thread_local_start); + thread_local_sz = ALIGNUP(0x10, thread_local_sz); + sp -= thread_local_sz; + task_thread_local_start = sp; + memcpy(task_thread_local_start, &_thread_local_start, thread_local_sz); + threadptr = task_thread_local_start - (&_thread_local_start - &_flash_rodata_start); + + /* Simulate the stack frame as it would be created by a context switch interrupt. */ + sp -= RV_STK_FRMSZ; + RvExcFrame *frame = (RvExcFrame *)sp; + memset(frame, 0, sizeof(*frame)); + /* Shifting RA into prvTaskExitError is necessary to make GDB backtrace ending inside that function. + Otherwise backtrace will end in the function laying just before prvTaskExitError in address space. */ + frame->ra = (UBaseType_t)prvTaskExitError + 4/*size of the nop insruction at the beginning of prvTaskExitError*/; + frame->mepc = (UBaseType_t)pxCode; + frame->a0 = (UBaseType_t)pvParameters; + frame->gp = (UBaseType_t)&__global_pointer$; + frame->tp = (UBaseType_t)threadptr; + + //TODO: IDF-2393 + return (StackType_t *)frame; +} + +// -------------------- Co-Processor ----------------------- + +// ------- Thread Local Storage Pointers Deletion Callbacks ------- + +#if ( CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS ) +void vPortTLSPointersDelCb( void * pxTCB ) +{ + /* Typecast pxTCB to StaticTask_t type to access TCB struct members. + * pvDummy15 corresponds to pvThreadLocalStoragePointers member of the TCB. + */ + StaticTask_t *tcb = ( StaticTask_t * )pxTCB; + + /* The TLSP deletion callbacks are stored at an offset of (configNUM_THREAD_LOCAL_STORAGE_POINTERS/2) */ + TlsDeleteCallbackFunction_t *pvThreadLocalStoragePointersDelCallback = ( TlsDeleteCallbackFunction_t * )( &( tcb->pvDummy15[ ( configNUM_THREAD_LOCAL_STORAGE_POINTERS / 2 ) ] ) ); + + /* We need to iterate over half the depth of the pvThreadLocalStoragePointers area + * to access all TLS pointers and their respective TLS deletion callbacks. + */ + for( int x = 0; x < ( configNUM_THREAD_LOCAL_STORAGE_POINTERS / 2 ); x++ ) + { + if ( pvThreadLocalStoragePointersDelCallback[ x ] != NULL ) //If del cb is set + { + /* In case the TLSP deletion callback has been overwritten by a TLS pointer, gracefully abort. */ + if ( !esp_ptr_executable( pvThreadLocalStoragePointersDelCallback[ x ] ) ) { + ESP_LOGE("FreeRTOS", "Fatal error: TLSP deletion callback at index %d overwritten with non-excutable pointer %p", x, pvThreadLocalStoragePointersDelCallback[ x ]); + abort(); + } + + pvThreadLocalStoragePointersDelCallback[ x ]( x, tcb->pvDummy15[ x ] ); //Call del cb + } + } +} +#endif // CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS + +// -------------------- Tick Handler ----------------------- + +extern void esp_vApplicationIdleHook(void); +extern void esp_vApplicationTickHook(void); + +BaseType_t xPortSysTickHandler(void) +{ +#if configBENCHMARK + portbenchmarkIntLatency(); +#endif //configBENCHMARK + traceISR_ENTER(SYSTICK_INTR_ID); + BaseType_t ret = xTaskIncrementTick(); + //Manually call the IDF tick hooks + esp_vApplicationTickHook(); + if(ret != pdFALSE) { + portYIELD_FROM_ISR(); + } else { + traceISR_EXIT(); + } + return ret; +} + +// ------------------- 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 (int i = 0; i < sizeof(str) / sizeof(str[0]); i++) { + dest = strcat(dest, str[i]); + } + esp_system_abort(buf); +} + +#if ( configUSE_TICK_HOOK > 0 ) +void vApplicationTickHook( void ) +{ + esp_vApplicationTickHook(); +} +#endif + +#if CONFIG_FREERTOS_USE_MINIMAL_IDLE_HOOK +/* +By default, the port uses vApplicationMinimalIdleHook() to run IDF style idle +hooks. However, users may also want to provide their own vApplicationMinimalIdleHook(). +In this case, we use to -Wl,--wrap option to wrap the user provided vApplicationMinimalIdleHook() +*/ +extern void __real_vApplicationMinimalIdleHook( void ); +void __wrap_vApplicationMinimalIdleHook( void ) +{ + esp_vApplicationIdleHook(); //Run IDF style hooks + __real_vApplicationMinimalIdleHook(); //Call the user provided vApplicationMinimalIdleHook() +} +#else // CONFIG_FREERTOS_USE_MINIMAL_IDLE_HOOK +void vApplicationMinimalIdleHook( void ) +{ + esp_vApplicationIdleHook(); //Run IDF style hooks +} +#endif // CONFIG_FREERTOS_USE_MINIMAL_IDLE_HOOK + +/* + * Hook function called during prvDeleteTCB() to cleanup any + * user defined static memory areas in the TCB. + */ +void vPortCleanUpTCB ( void *pxTCB ) +{ +#if ( CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS ) + /* Call TLS pointers deletion callbacks */ + vPortTLSPointersDelCb( pxTCB ); +#endif /* CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS */ +} + +/* ---------------------------------------------- Port Implementations ------------------------------------------------- + * + * ------------------------------------------------------------------------------------------------------------------ */ + +// ------------------ Critical Sections -------------------- + +void vPortEnterCritical(void) +{ + BaseType_t state = portSET_INTERRUPT_MASK_FROM_ISR(); + uxCriticalNesting++; + + if (uxCriticalNesting == 1) { + uxSavedInterruptState = state; + } +} + +void vPortExitCritical(void) +{ + if (uxCriticalNesting > 0) { + uxCriticalNesting--; + if (uxCriticalNesting == 0) { + portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptState); + } + } +} + +// ---------------------- Yielding ------------------------- + +int vPortSetInterruptMask(void) +{ + int ret; + unsigned old_mstatus = RV_CLEAR_CSR(mstatus, MSTATUS_MIE); + ret = REG_READ(INTERRUPT_CORE0_CPU_INT_THRESH_REG); + REG_WRITE(INTERRUPT_CORE0_CPU_INT_THRESH_REG, RVHAL_EXCM_LEVEL); + RV_SET_CSR(mstatus, old_mstatus & MSTATUS_MIE); + /** + * In theory, this function should not return immediately as there is a + * delay between the moment we mask the interrupt threshold register and + * the moment a potential lower-priority interrupt is triggered (as said + * above), it should have a delay of 2 machine cycles/instructions. + * + * However, in practice, this function has an epilogue of one instruction, + * thus the instruction masking the interrupt threshold register is + * followed by two instructions: `ret` and `csrrs` (RV_SET_CSR). + * That's why we don't need any additional nop instructions here. + */ + return ret; +} + +void vPortClearInterruptMask(int mask) +{ + REG_WRITE(INTERRUPT_CORE0_CPU_INT_THRESH_REG, mask); + /** + * The delay between the moment we unmask the interrupt threshold register + * and the moment the potential requested interrupt is triggered is not + * null: up to three machine cycles/instructions can be executed. + * + * When compilation size optimization is enabled, this function and its + * callers returning void will have NO epilogue, thus the instruction + * following these calls will be executed. + * + * If the requested interrupt is a context switch to a higher priority + * task then the one currently running, we MUST NOT execute any instruction + * before the interrupt effectively happens. + * In order to prevent this, force this routine to have a 3-instruction + * delay before exiting. + */ + asm volatile ( "nop" ); + asm volatile ( "nop" ); + asm volatile ( "nop" ); +} + +void vPortYield(void) +{ + if (uxInterruptNesting) { + vPortYieldFromISR(); + } else { + + esp_crosscore_int_send_yield(0); + /* There are 3-4 instructions of latency between triggering the software + interrupt and the CPU interrupt happening. Make sure it happened before + we return, otherwise vTaskDelay() may return and execute 1-2 + instructions before the delay actually happens. + + (We could use the WFI instruction here, but there is a chance that + the interrupt will happen while evaluating the other two conditions + for an instant yield, and if that happens then the WFI would be + waiting for the next interrupt to occur...) + */ + while (uxSchedulerRunning && uxCriticalNesting == 0 && REG_READ(SYSTEM_CPU_INTR_FROM_CPU_0_REG) != 0) {} + } +} + +void vPortYieldFromISR( void ) +{ + //traceISR_EXIT_TO_SCHEDULER(); + uxSchedulerRunning = 1; + xPortSwitchFlag = 1; +} + +void vPortYieldOtherCore(BaseType_t coreid) +{ + esp_crosscore_int_send_yield(coreid); +} diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/portasm.S b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/portasm.S new file mode 100644 index 0000000000..e27e9de2c1 --- /dev/null +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/portasm.S @@ -0,0 +1,104 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + + .global uxInterruptNesting + .global uxSchedulerRunning + .global xIsrStackTop + .global pxCurrentTCBs + .global vTaskSwitchContext + .global xPortSwitchFlag + + .section .text + +/** + * This function makes the RTOS aware about a ISR entering, it takes the + * current task stack saved, places into the TCB, loads the ISR stack + * the interrupted stack must be passed in a0. It needs to receive the + * ISR nesting code improvements + */ + + .global rtos_int_enter + .type rtos_int_enter, @function +rtos_int_enter: + /* preserve the return address */ + mv t1, ra + mv t2, a0 + + /* scheduler not enabled, jump directly to ISR handler */ + lw t0, uxSchedulerRunning + beq t0,zero, rtos_enter_end + + /* increments the ISR nesting count */ + la t3, uxInterruptNesting + lw t4, 0x0(t3) + addi t5,t4,1 + sw t5, 0x0(t3) + + /* If reached here from another low-prio ISR, skip stack pushing to TCB */ + bne t4,zero, rtos_enter_end + + /* Save current TCB and load the ISR stack */ + lw t0, pxCurrentTCBs + sw t2, 0x0(t0) + lw sp, xIsrStackTop + +rtos_enter_end: + mv ra, t1 + ret + +/** + * Recovers the next task to run stack pointer and place it into + * a0, then the interrupt handler can restore the context of + * the next task + */ + .global rtos_int_exit + .type rtos_int_exit, @function +rtos_int_exit: + /* may skip RTOS aware interrupt since scheduler was not started */ + lw t0, uxSchedulerRunning + beq t0,zero, rtos_exit_end + + /* update nesting interrupts counter */ + la t2, uxInterruptNesting + lw t3, 0x0(t2) + + /* Already zero, protect against underflow */ + beq t3, zero, isr_skip_decrement + addi t3,t3, -1 + sw t3, 0x0(t2) + +isr_skip_decrement: + + /* may still have interrupts pending, skip section below and exit */ + bne t3,zero,rtos_exit_end + + /* Schedule the next task if a yield is pending */ + la t0, xPortSwitchFlag + lw t2, 0x0(t0) + beq t2, zero, no_switch + + /* preserve return address and schedule next task + stack pointer for riscv should always be 16 byte aligned */ + addi sp,sp,-16 + sw ra, 0(sp) + /* vTaskSwitchContext(xCoreID) now expects xCoreID as an argument, so the assembly calls below have been modified. xCoreID is hard-wired to 0 for single-core risc-v. */ + li a0, 0 + call vTaskSwitchContext + lw ra, 0(sp) + addi sp, sp, 16 + + /* Clears the switch pending flag */ + la t0, xPortSwitchFlag + mv t2, zero + sw t2, 0x0(t0) + +no_switch: + /* Recover the stack of next task and prepare to exit : */ + lw a0, pxCurrentTCBs + lw a0, 0x0(a0) + +rtos_exit_end: + ret diff --git a/components/freertos/Kconfig b/components/freertos/Kconfig index e15770e081..134b181f42 100644 --- a/components/freertos/Kconfig +++ b/components/freertos/Kconfig @@ -5,7 +5,6 @@ menu "FreeRTOS" config FREERTOS_SMP bool "Run the SMP FreeRTOS kernel instead (FEATURE UNDER DEVELOPMENT)" - depends on IDF_TARGET_ESP32 default "n" help This will cause the FreeRTOS component to compile with the SMP FreeRTOS kernel instead.