mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-11-04 00:51:42 +01:00 
			
		
		
		
	- vTaskPreemptionDisable()/vTaskPreemptionEnable() are no longer available in single-core builds. - xTaskIncrementTick() calls must now be wrapped by critical section - Minimal Idle Task renamed to Passive Idle Task - Port critical section APIs updated
		
			
				
	
	
		
			509 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			509 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * SPDX-FileCopyrightText: 2022-2024 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/crosscore_int_ll.h"
 | 
						|
#include "hal/systimer_hal.h"
 | 
						|
#include "hal/systimer_ll.h"
 | 
						|
#include "riscv/rvruntime-frames.h"
 | 
						|
#include "riscv/rv_utils.h"
 | 
						|
#include "riscv/interrupt.h"
 | 
						|
#include "esp_private/crosscore_int.h"
 | 
						|
#include "esp_private/esp_int_wdt.h"
 | 
						|
#include "esp_private/periph_ctrl.h"
 | 
						|
#include "esp_private/systimer.h"
 | 
						|
#include "esp_attr.h"
 | 
						|
#include "esp_system.h"
 | 
						|
#include "esp_heap_caps_init.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 "port_systick.h"
 | 
						|
#include "portmacro.h"
 | 
						|
#include "esp_memory_utils.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
 | 
						|
 | 
						|
_Static_assert(portBYTE_ALIGNMENT == 16, "portBYTE_ALIGNMENT must be set to 16");
 | 
						|
#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
 | 
						|
/**
 | 
						|
 * offsetof() can not be used in asm code. Then we need make sure that
 | 
						|
 * PORT_OFFSET_PX_STACK and PORT_OFFSET_PX_END_OF_STACK have expected values.
 | 
						|
 * Macro used in the portasm.S instead of variables to save at least 4 instruction calls
 | 
						|
 * which accessing DRAM memory. This optimization saves CPU time in the interrupt handling.
 | 
						|
 */
 | 
						|
 | 
						|
_Static_assert(offsetof( StaticTask_t, pxDummy6 ) == PORT_OFFSET_PX_STACK);
 | 
						|
_Static_assert(offsetof( StaticTask_t, pxDummy8 ) == PORT_OFFSET_PX_END_OF_STACK);
 | 
						|
#endif // CONFIG_ESP_SYSTEM_HW_STACK_GUARD
 | 
						|
 | 
						|
/* ---------------------------------------------------- Variables ------------------------------------------------------
 | 
						|
 *
 | 
						|
 * ------------------------------------------------------------------------------------------------------------------ */
 | 
						|
 | 
						|
BaseType_t uxSchedulerRunning = 0;  // Duplicate of xSchedulerRunning, accessible to port files
 | 
						|
volatile UBaseType_t uxInterruptNesting = 0;
 | 
						|
portMUX_TYPE port_xTaskLock = portMUX_INITIALIZER_UNLOCKED;
 | 
						|
portMUX_TYPE port_xISRLock = portMUX_INITIALIZER_UNLOCKED;
 | 
						|
volatile BaseType_t xPortSwitchFlag = 0;
 | 
						|
__attribute__((aligned(16))) StackType_t xIsrStack[configISR_STACK_SIZE];
 | 
						|
StackType_t *xIsrStackTop = &xIsrStack[0] + (configISR_STACK_SIZE & (~((portPOINTER_SIZE_TYPE)portBYTE_ALIGNMENT_MASK)));
 | 
						|
 | 
						|
// Variables used for IDF style critical sections. These are orthogonal to FreeRTOS critical sections
 | 
						|
static UBaseType_t port_uxCriticalNestingIDF = 0;
 | 
						|
static UBaseType_t port_uxCriticalOldInterruptStateIDF = 0;
 | 
						|
 | 
						|
/* ------------------------------------------------ IDF Compatibility --------------------------------------------------
 | 
						|
 * - These need to be defined for IDF to compile
 | 
						|
 * ------------------------------------------------------------------------------------------------------------------ */
 | 
						|
 | 
						|
// ------------------ Critical Sections --------------------
 | 
						|
 | 
						|
void vPortEnterCritical(void)
 | 
						|
{
 | 
						|
    // Save current interrupt threshold and disable interrupts
 | 
						|
    UBaseType_t old_thresh = ulPortSetInterruptMask();
 | 
						|
    // Update the IDF critical nesting count
 | 
						|
    port_uxCriticalNestingIDF++;
 | 
						|
    if (port_uxCriticalNestingIDF == 1) {
 | 
						|
        // Save a copy of the old interrupt threshold
 | 
						|
        port_uxCriticalOldInterruptStateIDF = (UBaseType_t) old_thresh;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void vPortExitCritical(void)
 | 
						|
{
 | 
						|
    if (port_uxCriticalNestingIDF > 0) {
 | 
						|
        port_uxCriticalNestingIDF--;
 | 
						|
        if (port_uxCriticalNestingIDF == 0) {
 | 
						|
            // Restore the saved interrupt threshold
 | 
						|
            vPortClearInterruptMask((int)port_uxCriticalOldInterruptStateIDF);
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
// ----------------------- System --------------------------
 | 
						|
 | 
						|
#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);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/* ---------------------------------------------- Port Implementations -------------------------------------------------
 | 
						|
 * Implementations of Porting Interface functions
 | 
						|
 * ------------------------------------------------------------------------------------------------------------------ */
 | 
						|
 | 
						|
// --------------------- Interrupts ------------------------
 | 
						|
 | 
						|
UBaseType_t ulPortSetInterruptMask(void)
 | 
						|
{
 | 
						|
    int ret;
 | 
						|
    unsigned old_mstatus = RV_CLEAR_CSR(mstatus, MSTATUS_MIE);
 | 
						|
    ret = REG_READ(INTERRUPT_CURRENT_CORE_INT_THRESH_REG);
 | 
						|
    REG_WRITE(INTERRUPT_CURRENT_CORE_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(UBaseType_t mask)
 | 
						|
{
 | 
						|
    REG_WRITE(INTERRUPT_CURRENT_CORE_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" );
 | 
						|
}
 | 
						|
 | 
						|
BaseType_t xPortCheckIfInISR(void)
 | 
						|
{
 | 
						|
    return uxInterruptNesting;
 | 
						|
}
 | 
						|
 | 
						|
// ------------------ Critical Sections --------------------
 | 
						|
 | 
						|
#if ( configNUMBER_OF_CORES > 1 )
 | 
						|
void IRAM_ATTR vPortTakeLock( portMUX_TYPE *lock )
 | 
						|
{
 | 
						|
    spinlock_acquire( lock, portMUX_NO_TIMEOUT);
 | 
						|
}
 | 
						|
 | 
						|
void IRAM_ATTR vPortReleaseLock( portMUX_TYPE *lock )
 | 
						|
{
 | 
						|
    spinlock_release( lock );
 | 
						|
}
 | 
						|
#endif /* configNUMBER_OF_CORES > 1 */
 | 
						|
 | 
						|
// ---------------------- Yielding -------------------------
 | 
						|
 | 
						|
void vPortYield(void)
 | 
						|
{
 | 
						|
    // TODO: IDF-8113
 | 
						|
    const int core_id = 0;
 | 
						|
 | 
						|
    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 && crosscore_int_ll_get_state(core_id) != 0) {}
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
void vPortYieldFromISR( void )
 | 
						|
{
 | 
						|
    //traceISR_EXIT_TO_SCHEDULER();
 | 
						|
    uxSchedulerRunning = 1;
 | 
						|
    xPortSwitchFlag = 1;
 | 
						|
}
 | 
						|
// ----------------------- System --------------------------
 | 
						|
 | 
						|
// ------------------- Run Time Stats ----------------------
 | 
						|
 | 
						|
// --------------------- TCB Cleanup -----------------------
 | 
						|
 | 
						|
#if ( CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS )
 | 
						|
static 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 */
 | 
						|
 | 
						|
void vPortTCBPreDeleteHook( void *pxTCB )
 | 
						|
{
 | 
						|
    #if ( CONFIG_FREERTOS_TASK_PRE_DELETION_HOOK )
 | 
						|
        /* Call the user defined task pre-deletion hook */
 | 
						|
        extern void vTaskPreDeletionHook( void * pxTCB );
 | 
						|
        vTaskPreDeletionHook( pxTCB );
 | 
						|
    #endif /* CONFIG_FREERTOS_TASK_PRE_DELETION_HOOK */
 | 
						|
 | 
						|
    #if ( CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP )
 | 
						|
        /*
 | 
						|
         * If the user is using the legacy task pre-deletion hook, call it.
 | 
						|
         * Todo: Will be removed in IDF-8097
 | 
						|
         */
 | 
						|
        #warning "CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP is deprecated. Use CONFIG_FREERTOS_TASK_PRE_DELETION_HOOK instead."
 | 
						|
        extern void vPortCleanUpTCB( void * pxTCB );
 | 
						|
        vPortCleanUpTCB( pxTCB );
 | 
						|
    #endif /* CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP */
 | 
						|
 | 
						|
    #if ( CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS )
 | 
						|
        /* Call TLS pointers deletion callbacks */
 | 
						|
        vPortTLSPointersDelCb( pxTCB );
 | 
						|
    #endif /* CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS */
 | 
						|
}
 | 
						|
 | 
						|
/* ------------------------------------------------ FreeRTOS Portable --------------------------------------------------
 | 
						|
 * - Provides implementation for functions required by FreeRTOS
 | 
						|
 * - Declared in portable.h
 | 
						|
 * ------------------------------------------------------------------------------------------------------------------ */
 | 
						|
 | 
						|
// ----------------- Scheduler Start/End -------------------
 | 
						|
 | 
						|
BaseType_t xPortStartScheduler(void)
 | 
						|
{
 | 
						|
    uxInterruptNesting = 0;
 | 
						|
    port_uxCriticalNestingIDF = 0;
 | 
						|
    uxSchedulerRunning = 0;
 | 
						|
 | 
						|
    /* Setup the hardware to generate the tick. */
 | 
						|
    vPortSetupTimer();
 | 
						|
 | 
						|
    esprv_int_set_threshold(1); /* set global INTC masking level */
 | 
						|
    rv_utils_intr_global_enable();
 | 
						|
 | 
						|
    vPortYield();
 | 
						|
 | 
						|
    /*Should not get here*/
 | 
						|
    return pdFALSE;
 | 
						|
}
 | 
						|
 | 
						|
void vPortEndScheduler(void)
 | 
						|
{
 | 
						|
    /* very unlikely this function will be called, so just trap here */
 | 
						|
    abort();
 | 
						|
}
 | 
						|
 | 
						|
// ------------------------ Stack --------------------------
 | 
						|
 | 
						|
/**
 | 
						|
 * @brief Align stack pointer in a downward growing stack
 | 
						|
 *
 | 
						|
 * This macro is used to round a stack pointer downwards to the nearest n-byte boundary, where n is a power of 2.
 | 
						|
 * This macro is generally used when allocating aligned areas on a downward growing stack.
 | 
						|
 */
 | 
						|
#define STACKPTR_ALIGN_DOWN(n, ptr)     ((ptr) & (~((n)-1)))
 | 
						|
 | 
						|
/**
 | 
						|
 * @brief Allocate and initialize GCC TLS area
 | 
						|
 *
 | 
						|
 * This function allocates and initializes the area on the stack used to store GCC TLS (Thread Local Storage) variables.
 | 
						|
 * - The area's size is derived from the TLS section's linker variables, and rounded up to a multiple of 16 bytes
 | 
						|
 * - The allocated area is aligned to a 16-byte aligned address
 | 
						|
 * - The TLS variables in the area are then initialized
 | 
						|
 *
 | 
						|
 * Each task access the TLS variables using the THREADPTR register plus an offset to obtain the address of the variable.
 | 
						|
 * The value for the THREADPTR register is also calculated by this function, and that value should be use to initialize
 | 
						|
 * the THREADPTR register.
 | 
						|
 *
 | 
						|
 * @param[in] uxStackPointer Current stack pointer address
 | 
						|
 * @param[out] ret_threadptr_reg_init Calculated THREADPTR register initialization value
 | 
						|
 * @return Stack pointer that points to the TLS area
 | 
						|
 */
 | 
						|
FORCE_INLINE_ATTR UBaseType_t uxInitialiseStackTLS(UBaseType_t uxStackPointer, uint32_t *ret_threadptr_reg_init)
 | 
						|
{
 | 
						|
    /*
 | 
						|
    LOW ADDRESS
 | 
						|
            |---------------------------|   Linker Symbols
 | 
						|
            | Section                   |   --------------
 | 
						|
            | .flash.tls                |
 | 
						|
         0x0|---------------------------| <- _thread_local_start
 | 
						|
            | .tbss                     | ^
 | 
						|
            |                           | |
 | 
						|
            | int example;              | | tls_area_size
 | 
						|
            |                           | |
 | 
						|
            | .tdata                    | V
 | 
						|
            |---------------------------| <- _thread_local_end
 | 
						|
            | Other data                |
 | 
						|
            | ...                       |
 | 
						|
            |---------------------------|
 | 
						|
    HIGH ADDRESS
 | 
						|
    */
 | 
						|
    // Calculate TLS area size and round up to multiple of 16 bytes.
 | 
						|
    extern char _thread_local_start, _thread_local_end;
 | 
						|
    const uint32_t tls_area_size = ALIGNUP(16, (uint32_t)&_thread_local_end - (uint32_t)&_thread_local_start);
 | 
						|
    // TODO: check that TLS area fits the stack
 | 
						|
 | 
						|
    // Allocate space for the TLS area on the stack. The area must be aligned to 16-bytes
 | 
						|
    uxStackPointer = STACKPTR_ALIGN_DOWN(16, uxStackPointer - (UBaseType_t)tls_area_size);
 | 
						|
    // Initialize the TLS area with the initialization values of each TLS variable
 | 
						|
    memcpy((void *)uxStackPointer, &_thread_local_start, tls_area_size);
 | 
						|
 | 
						|
    // Save tls start address
 | 
						|
    *ret_threadptr_reg_init = (uint32_t)uxStackPointer;
 | 
						|
    return uxStackPointer;
 | 
						|
}
 | 
						|
 | 
						|
#if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
 | 
						|
static void vPortTaskWrapper(TaskFunction_t pxCode, void *pvParameters)
 | 
						|
{
 | 
						|
    __asm__ volatile(".cfi_undefined ra");  // tell to debugger that it's outermost (inital) frame
 | 
						|
    extern void __attribute__((noreturn)) panic_abort(const char *details);
 | 
						|
    static char DRAM_ATTR msg[80] = "FreeRTOS: FreeRTOS Task \"\0";
 | 
						|
    pxCode(pvParameters);
 | 
						|
    /* FreeRTOS tasks should not return. Log the task name and abort. */
 | 
						|
    /* We cannot use s(n)printf because it is in flash */
 | 
						|
    strcat(msg, pcTaskGetName(NULL));
 | 
						|
    strcat(msg, "\" should not return, Aborting now!");
 | 
						|
    panic_abort(msg);
 | 
						|
}
 | 
						|
#endif // CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
 | 
						|
 | 
						|
/**
 | 
						|
 * @brief Initialize the task's starting interrupt stack frame
 | 
						|
 *
 | 
						|
 * This function initializes the task's starting interrupt stack frame. The dispatcher will use this stack frame in a
 | 
						|
 * context restore routine. Therefore, the starting stack frame must be initialized as if the task was interrupted right
 | 
						|
 * before its first instruction is called.
 | 
						|
 *
 | 
						|
 * - The stack frame is allocated to a 16-byte aligned address
 | 
						|
 *
 | 
						|
 * @param[in] uxStackPointer Current stack pointer address
 | 
						|
 * @param[in] pxCode Task function
 | 
						|
 * @param[in] pvParameters Task function's parameter
 | 
						|
 * @param[in] threadptr_reg_init THREADPTR register initialization value
 | 
						|
 * @return Stack pointer that points to the stack frame
 | 
						|
 */
 | 
						|
FORCE_INLINE_ATTR UBaseType_t uxInitialiseStackFrame(UBaseType_t uxStackPointer, TaskFunction_t pxCode, void *pvParameters, uint32_t threadptr_reg_init)
 | 
						|
{
 | 
						|
    /*
 | 
						|
    Allocate space for the task's starting interrupt stack frame.
 | 
						|
    - The stack frame must be allocated to a 16-byte aligned address.
 | 
						|
    - We use RV_STK_FRMSZ (instead of sizeof(RvExcFrame)) as it rounds up the total size to a multiple of 16.
 | 
						|
    */
 | 
						|
    uxStackPointer = STACKPTR_ALIGN_DOWN(16, uxStackPointer - RV_STK_FRMSZ);
 | 
						|
 | 
						|
    // Clear the entire interrupt stack frame
 | 
						|
    RvExcFrame *frame = (RvExcFrame *)uxStackPointer;
 | 
						|
    memset(frame, 0, sizeof(RvExcFrame));
 | 
						|
 | 
						|
    /* Initialize the stack frame. */
 | 
						|
    extern uint32_t __global_pointer$;
 | 
						|
    #if CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
 | 
						|
        frame->mepc = (UBaseType_t)vPortTaskWrapper;
 | 
						|
        frame->a0 = (UBaseType_t)pxCode;
 | 
						|
        frame->a1 = (UBaseType_t)pvParameters;
 | 
						|
    #else
 | 
						|
        frame->mepc = (UBaseType_t)pxCode;
 | 
						|
        frame->a0 = (UBaseType_t)pvParameters;
 | 
						|
    #endif // CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER
 | 
						|
    frame->gp = (UBaseType_t)&__global_pointer$;
 | 
						|
    frame->tp = (UBaseType_t)threadptr_reg_init;
 | 
						|
 | 
						|
    return uxStackPointer;
 | 
						|
}
 | 
						|
 | 
						|
StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters)
 | 
						|
{
 | 
						|
#ifdef __clang_analyzer__
 | 
						|
    // Teach clang-tidy that pxTopOfStack cannot be a pointer to const
 | 
						|
    volatile StackType_t * pxTemp = pxTopOfStack;
 | 
						|
    pxTopOfStack = pxTemp;
 | 
						|
#endif /*__clang_analyzer__ */
 | 
						|
    /*
 | 
						|
    HIGH ADDRESS
 | 
						|
    |---------------------------| <- pxTopOfStack on entry
 | 
						|
    | TLS Variables             |
 | 
						|
    | ------------------------- | <- Start of useable stack
 | 
						|
    | Starting stack frame      |
 | 
						|
    | ------------------------- | <- pxTopOfStack on return (which is the tasks current SP)
 | 
						|
    |             |             |
 | 
						|
    |             |             |
 | 
						|
    |             V             |
 | 
						|
    ----------------------------- <- Bottom of stack
 | 
						|
    LOW ADDRESS
 | 
						|
 | 
						|
    - All stack areas are aligned to 16 byte boundary
 | 
						|
    - We use UBaseType_t for all of stack area initialization functions for more convenient pointer arithmetic
 | 
						|
    */
 | 
						|
 | 
						|
    UBaseType_t uxStackPointer = (UBaseType_t)pxTopOfStack;
 | 
						|
    configASSERT((uxStackPointer & portBYTE_ALIGNMENT_MASK) == 0);
 | 
						|
 | 
						|
    // Initialize GCC TLS area
 | 
						|
    uint32_t threadptr_reg_init;
 | 
						|
    uxStackPointer = uxInitialiseStackTLS(uxStackPointer, &threadptr_reg_init);
 | 
						|
    configASSERT((uxStackPointer & portBYTE_ALIGNMENT_MASK) == 0);
 | 
						|
 | 
						|
    // Initialize the starting interrupt stack frame
 | 
						|
    uxStackPointer = uxInitialiseStackFrame(uxStackPointer, pxCode, pvParameters, threadptr_reg_init);
 | 
						|
    configASSERT((uxStackPointer & portBYTE_ALIGNMENT_MASK) == 0);
 | 
						|
 | 
						|
    // Return the task's current stack pointer address which should point to the starting interrupt stack frame
 | 
						|
    return (StackType_t *)uxStackPointer;
 | 
						|
    //TODO: IDF-2393
 | 
						|
}
 | 
						|
 | 
						|
// ------------------- 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
 | 
						|
 | 
						|
extern void esp_vApplicationIdleHook(void);
 | 
						|
#if CONFIG_FREERTOS_USE_PASSIVE_IDLE_HOOK
 | 
						|
/*
 | 
						|
By default, the port uses vApplicationPassiveIdleHook() to run IDF style idle
 | 
						|
hooks. However, users may also want to provide their own vApplicationPassiveIdleHook().
 | 
						|
In this case, we use to -Wl,--wrap option to wrap the user provided vApplicationPassiveIdleHook()
 | 
						|
*/
 | 
						|
extern void __real_vApplicationPassiveIdleHook( void );
 | 
						|
void __wrap_vApplicationPassiveIdleHook( void )
 | 
						|
{
 | 
						|
    esp_vApplicationIdleHook(); //Run IDF style hooks
 | 
						|
    __real_vApplicationPassiveIdleHook(); //Call the user provided vApplicationPassiveIdleHook()
 | 
						|
}
 | 
						|
#else // CONFIG_FREERTOS_USE_PASSIVE_IDLE_HOOK
 | 
						|
void vApplicationPassiveIdleHook( void )
 | 
						|
{
 | 
						|
    esp_vApplicationIdleHook(); //Run IDF style hooks
 | 
						|
}
 | 
						|
#endif // CONFIG_FREERTOS_USE_PASSIVE_IDLE_HOOK
 |