Procházet zdrojové kódy

freertos-smp: add support for RISC-V targets oon FreeRTOS SMP

TBD: Initial commit. Enables risc-v port.
Sudeep Mohanty před 3 roky
rodič
revize
8fd953c627

+ 18 - 0
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

+ 328 - 0
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 <assert.h>         //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 */

+ 652 - 0
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 <stdint.h>
+#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 <stdlib.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#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 <limits.h>
+
+/* [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

+ 729 - 0
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 <string.h>
+#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);
+}

+ 104 - 0
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

+ 0 - 1
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.