diff --git a/components/esp_common/src/int_wdt.c b/components/esp_common/src/int_wdt.c index a2de13404d..da2f880cc1 100644 --- a/components/esp_common/src/int_wdt.c +++ b/components/esp_common/src/int_wdt.c @@ -1,9 +1,9 @@ -// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at - +// // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software @@ -12,14 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "sdkconfig.h" #include #include #include #include +#include "sdkconfig.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#include +#include "esp_types.h" #include "esp_err.h" #include "esp_intr_alloc.h" #include "esp_attr.h" @@ -29,6 +29,7 @@ #include "driver/periph_ctrl.h" #include "esp_int_wdt.h" #include "esp_private/system_internal.h" +#include "hal/cpu_hal.h" #include "hal/timer_types.h" #include "hal/wdt_hal.h" #include "hal/interrupt_controller_hal.h" @@ -45,7 +46,7 @@ static wdt_hal_context_t iwdt_context; #if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX /* - * This parameter is indicates the response time of Interrupt watchdog to + * This parameter is used to indicate the response time of Interrupt watchdog to * identify the live lock. */ #define IWDT_LIVELOCK_TIMEOUT_MS (20) @@ -58,8 +59,9 @@ extern uint32_t _l4_intr_livelock_counter, _l4_intr_livelock_max; //Not static; the ISR assembly checks this. bool int_wdt_app_cpu_ticked = false; -static void IRAM_ATTR tick_hook(void) { - if (xPortGetCoreID()!=0) { +static void IRAM_ATTR tick_hook(void) +{ + if (cpu_hal_get_core_id() != 0) { int_wdt_app_cpu_ticked = true; } else { //Only feed wdt if app cpu also ticked. @@ -70,11 +72,11 @@ static void IRAM_ATTR tick_hook(void) { #if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX _l4_intr_livelock_counter = 0; wdt_hal_config_stage(&iwdt_context, WDT_STAGE0, - CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/IWDT_TICKS_PER_US/(_l4_intr_livelock_max+1), WDT_STAGE_ACTION_INT); //Set timeout before interrupt + CONFIG_ESP_INT_WDT_TIMEOUT_MS * 1000 / IWDT_TICKS_PER_US / (_l4_intr_livelock_max + 1), WDT_STAGE_ACTION_INT); //Set timeout before interrupt #else - wdt_hal_config_stage(&iwdt_context, WDT_STAGE0, CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/IWDT_TICKS_PER_US, WDT_STAGE_ACTION_INT); //Set timeout before interrupt + wdt_hal_config_stage(&iwdt_context, WDT_STAGE0, CONFIG_ESP_INT_WDT_TIMEOUT_MS * 1000 / IWDT_TICKS_PER_US, WDT_STAGE_ACTION_INT); //Set timeout before interrupt #endif - wdt_hal_config_stage(&iwdt_context, WDT_STAGE1, 2*CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/IWDT_TICKS_PER_US, WDT_STAGE_ACTION_RESET_SYSTEM); //Set timeout before reset + wdt_hal_config_stage(&iwdt_context, WDT_STAGE1, 2 * CONFIG_ESP_INT_WDT_TIMEOUT_MS * 1000 / IWDT_TICKS_PER_US, WDT_STAGE_ACTION_RESET_SYSTEM); //Set timeout before reset wdt_hal_feed(&iwdt_context); wdt_hal_write_protect_enable(&iwdt_context); int_wdt_app_cpu_ticked = false; @@ -82,32 +84,31 @@ static void IRAM_ATTR tick_hook(void) { } } #else -static void IRAM_ATTR tick_hook(void) { +static void IRAM_ATTR tick_hook(void) +{ #if !CONFIG_FREERTOS_UNICORE - if (xPortGetCoreID()!=0) { + if (cpu_hal_get_core_id() != 0) { return; } #endif //Todo: Check if there's a way to avoid reconfiguring the stages on each feed. wdt_hal_write_protect_disable(&iwdt_context); //Reconfigure stage timeouts - wdt_hal_config_stage(&iwdt_context, WDT_STAGE0, CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/IWDT_TICKS_PER_US, WDT_STAGE_ACTION_INT); //Set timeout before interrupt - wdt_hal_config_stage(&iwdt_context, WDT_STAGE1, 2*CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/IWDT_TICKS_PER_US, WDT_STAGE_ACTION_RESET_SYSTEM); //Set timeout before reset + wdt_hal_config_stage(&iwdt_context, WDT_STAGE0, CONFIG_ESP_INT_WDT_TIMEOUT_MS * 1000 / IWDT_TICKS_PER_US, WDT_STAGE_ACTION_INT); //Set timeout before interrupt + wdt_hal_config_stage(&iwdt_context, WDT_STAGE1, 2 * CONFIG_ESP_INT_WDT_TIMEOUT_MS * 1000 / IWDT_TICKS_PER_US, WDT_STAGE_ACTION_RESET_SYSTEM); //Set timeout before reset wdt_hal_feed(&iwdt_context); wdt_hal_write_protect_enable(&iwdt_context); } #endif -void esp_int_wdt_init(void) { +void esp_int_wdt_init(void) +{ periph_module_enable(PERIPH_TIMG1_MODULE); //The timer configs initially are set to 5 seconds, to make sure the CPU can start up. The tick hook sets //it to their actual value. wdt_hal_init(&iwdt_context, IWDT_INSTANCE, IWDT_PRESCALER, true); wdt_hal_write_protect_disable(&iwdt_context); - //The timer configs initially are set to 5 seconds, to make sure the CPU can start up. The tick hook sets - //it to their actual value. - //1st stage timeout: interrupt wdt_hal_config_stage(&iwdt_context, WDT_STAGE0, IWDT_INITIAL_TIMEOUT_S * 1000000 / IWDT_TICKS_PER_US, WDT_STAGE_ACTION_INT); //2nd stage timeout: reset system @@ -119,18 +120,15 @@ void esp_int_wdt_init(void) { void esp_int_wdt_cpu_init(void) { - assert((CONFIG_ESP_INT_WDT_TIMEOUT_MS >= (portTICK_PERIOD_MS<<1)) && "Interrupt watchdog timeout needs to meet twice the RTOS tick period!"); - esp_register_freertos_tick_hook_for_cpu(tick_hook, xPortGetCoreID()); + assert((CONFIG_ESP_INT_WDT_TIMEOUT_MS >= (portTICK_PERIOD_MS << 1)) && "Interrupt watchdog timeout needs to meet twice the RTOS tick period!"); + esp_register_freertos_tick_hook_for_cpu(tick_hook, cpu_hal_get_core_id()); ESP_INTR_DISABLE(WDT_INT_NUM); - intr_matrix_set(xPortGetCoreID(), ETS_TG1_WDT_LEVEL_INTR_SOURCE, WDT_INT_NUM); + intr_matrix_set(cpu_hal_get_core_id(), ETS_TG1_WDT_LEVEL_INTR_SOURCE, WDT_INT_NUM); - /* Set the type and priority to cache error interrupts, if supported. */ -#if SOC_INTERRUPT_TYPE_CAN_SET - interrupt_controller_hal_set_type(WDT_INT_NUM, INTR_TYPE_LEVEL); -#endif - -#if SOC_INTERRUPT_LEVEL_CAN_SET - interrupt_controller_hal_set_level(WDT_INT_NUM, SOC_INTERRUPT_LEVEL_MEDIUM); + /* Set the type and priority to watch dog interrupts */ +#if SOC_CPU_HAS_FLEXIBLE_INTC + interrupt_controller_hal_set_int_type(WDT_INT_NUM, INTR_TYPE_LEVEL); + interrupt_controller_hal_set_int_level(WDT_INT_NUM, SOC_INTERRUPT_LEVEL_MEDIUM); #endif #if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX @@ -140,15 +138,15 @@ void esp_int_wdt_cpu_init(void) */ _l4_intr_livelock_counter = 0; if (soc_has_cache_lock_bug()) { - assert((portTICK_PERIOD_MS<<1) <= IWDT_LIVELOCK_TIMEOUT_MS); - assert(CONFIG_ESP_INT_WDT_TIMEOUT_MS >= (IWDT_LIVELOCK_TIMEOUT_MS*3)); - _l4_intr_livelock_max = CONFIG_ESP_INT_WDT_TIMEOUT_MS/IWDT_LIVELOCK_TIMEOUT_MS - 1; + assert((portTICK_PERIOD_MS << 1) <= IWDT_LIVELOCK_TIMEOUT_MS); + assert(CONFIG_ESP_INT_WDT_TIMEOUT_MS >= (IWDT_LIVELOCK_TIMEOUT_MS * 3)); + _l4_intr_livelock_max = CONFIG_ESP_INT_WDT_TIMEOUT_MS / IWDT_LIVELOCK_TIMEOUT_MS - 1; } #endif - //We do not register a handler for the interrupt because it is interrupt level 4 which - //is not servicable from C. Instead, xtensa_vectors.S has a call to the panic handler for - //this interrupt. + // We do not register a handler for the watchdog interrupt because: + // 1. Interrupt level 4 on Xtensa architecture is not servicable from C + // 2. Instead, we set the entry of watchdog interrupt to the panic handler, see riscv/vector.S and xtensa_vectors.S ESP_INTR_ENABLE(WDT_INT_NUM); } diff --git a/components/esp_system/include/esp_intr_alloc.h b/components/esp_system/include/esp_intr_alloc.h index 6c9963c176..33f70b9597 100644 --- a/components/esp_system/include/esp_intr_alloc.h +++ b/components/esp_system/include/esp_intr_alloc.h @@ -1,4 +1,4 @@ -// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,8 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef __ESP_INTR_ALLOC_H__ -#define __ESP_INTR_ALLOC_H__ +#pragma once #include #include @@ -37,24 +36,24 @@ extern "C" { */ //Keep the LEVELx values as they are here; they match up with (1<> 1) + 1; +} + /**@}*/ #ifdef __cplusplus } #endif - -#endif diff --git a/components/esp_system/intr_alloc.c b/components/esp_system/intr_alloc.c index 22650cfc25..9327b0ff8c 100644 --- a/components/esp_system/intr_alloc.c +++ b/components/esp_system/intr_alloc.c @@ -1,9 +1,9 @@ -// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at - +// // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "sdkconfig.h" #include #include #include @@ -21,6 +20,7 @@ #include #include #include +#include "sdkconfig.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_err.h" @@ -48,7 +48,8 @@ Define this to debug the choices made when allocating the interrupt. This leads output within a critical region, which can lead to weird effects like e.g. the interrupt watchdog being triggered, that is why it is separate from the normal LOG* scheme. */ -//define DEBUG_INT_ALLOC_DECISIONS +// #define DEBUG_INT_ALLOC_DECISIONS + #ifdef DEBUG_INT_ALLOC_DECISIONS # define ALCHLOG(...) ESP_EARLY_LOGD(TAG, __VA_ARGS__) #else @@ -237,6 +238,8 @@ static bool is_vect_desc_usable(vector_desc_t *vd, int flags, int cpu, int force ALCHLOG("....Unusable: special-purpose int"); return false; } + +#ifndef SOC_CPU_HAS_FLEXIBLE_INTC //Check if the interrupt level is acceptable if (!(flags&(1<flags&VECDESC_FL_RESERVED) { ALCHLOG("....Unusable: reserved at runtime."); @@ -551,14 +556,11 @@ esp_err_t esp_intr_alloc_intrstatus(int source, int flags, uint32_t intrstatusre interrupt_controller_hal_set_int_handler(intr, handler, arg); #endif } -#ifdef __XTENSA__ // TODO ESP32-C3 IDF-2126 - if (flags&ESP_INTR_FLAG_EDGE) xthal_set_intclear(1 << intr); -#else + if (flags & ESP_INTR_FLAG_EDGE) { - ESP_INTR_DISABLE(intr); - esprv_intc_int_set_priority(intr, 0); + interrupt_controller_hal_edge_int_acknowledge(intr); } -#endif + vd->source=source; } if (flags&ESP_INTR_FLAG_IRAM) { @@ -585,11 +587,16 @@ esp_err_t esp_intr_alloc_intrstatus(int source, int flags, uint32_t intrstatusre esp_intr_disable(ret); } -#if CONFIG_IDF_TARGET_ESP32C3 - // TODO ESP32-C3 IDF-2126, these need to be set or the new interrupt won't fire, but are currently hard-coded - // for priority and level... - esprv_intc_int_set_priority(intr, 1); - esprv_intc_int_set_type(BIT(intr), INTR_TYPE_LEVEL); +#ifdef SOC_CPU_HAS_FLEXIBLE_INTC + //Extract the level from the interrupt passed flags + int level = esp_intr_flags_to_level(flags); + interrupt_controller_hal_set_int_level(intr, level); + + if (flags & ESP_INTR_FLAG_EDGE) { + interrupt_controller_hal_set_int_type(intr, INTTP_EDGE); + } else { + interrupt_controller_hal_set_int_type(intr, INTTP_LEVEL); + } #endif portEXIT_CRITICAL(&spinlock); diff --git a/components/freertos/port/riscv/port.c b/components/freertos/port/riscv/port.c index 6c25ad11ad..a2256b9add 100644 --- a/components/freertos/port/riscv/port.c +++ b/components/freertos/port/riscv/port.c @@ -77,19 +77,23 @@ #include #include "FreeRTOS.h" #include "task.h" -#include "sdkconfig.h" #include "portmacro.h" -#include "riscv/interrupt.h" -#include "riscv/rvruntime-frames.h" + +#include "sdkconfig.h" + #include "soc/periph_defs.h" #include "soc/system_reg.h" -#include "soc/interrupt_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_system.h" #include "esp_intr_alloc.h" +#include "esp_private/crosscore_int.h" +#include "esp_attr.h" #include "esp_log.h" /** @@ -102,15 +106,14 @@ 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))); static const char *TAG = "cpu_start"; // [refactor-todo]: might be appropriate to change in the future, but -static void vPortSysTickHandler(void); +static void vPortSysTickHandler(void *arg); static void vPortSetupTimer(void); -static void vPortSetupSoftwareInterrupt(void); -static void vPortSoftwareInterrupt(void); static void prvTaskExitError(void); extern void esprv_intc_int_set_threshold(int); // FIXME, this function is in ROM only @@ -121,7 +124,6 @@ void vPortEnterCritical(void) uxCriticalNesting++; if (uxCriticalNesting == 1) { - //portDISABLE_INTERRUPTS(); uxSavedInterruptState = state; } } @@ -132,7 +134,6 @@ void vPortExitCritical(void) uxCriticalNesting--; if (uxCriticalNesting == 0) { portEXIT_CRITICAL_NESTED(uxSavedInterruptState); - //portENABLE_INTERRUPTS(); } } } @@ -143,16 +144,9 @@ void vPortExitCritical(void) */ void vPortSetupTimer(void) { - /* register the interrupt handler */ - intr_handler_set(ETS_SYSTICK_INUM, (intr_handler_t)&vPortSysTickHandler, NULL); - - /* pass the timer interrupt through the interrupt matrix */ - intr_matrix_route(ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE, ETS_SYSTICK_INUM); - - /* enable the interrupt in the INTC */ - esprv_intc_int_enable(BIT(ETS_SYSTICK_INUM)); - esprv_intc_int_set_type(BIT(ETS_SYSTICK_INUM), INTR_TYPE_LEVEL); - esprv_intc_int_set_priority(ETS_SYSTICK_INUM, 1); + /* set system timer interrupt vector */ + esp_err_t err = esp_intr_alloc(ETS_SYSTIMER_TARGET0_EDGE_INTR_SOURCE, ESP_INTR_FLAG_IRAM, vPortSysTickHandler, NULL, NULL); + assert(err == ESP_OK); /* configure the timer */ systimer_hal_init(); @@ -163,24 +157,6 @@ void vPortSetupTimer(void) systimer_hal_connect_alarm_counter(SYSTIMER_ALARM_0, SYSTIMER_COUNTER_1); } -/* setup software interrupt */ -void vPortSetupSoftwareInterrupt(void) -{ - /* register the interrupt handler, see interrupt.h */ - intr_handler_set(ETS_CPU_INTR0_INUM, (intr_handler_t)&vPortSoftwareInterrupt, NULL); - - /* pass the "FROM_CPU_0", a.k.a. cross-core interrupt, through the interrupt matrix */ - intr_matrix_route(ETS_FROM_CPU_INTR0_SOURCE, ETS_CPU_INTR0_INUM); - - /* enable the interrupt in the INTC */ - esprv_intc_int_enable(BIT(ETS_CPU_INTR0_INUM)); - esprv_intc_int_set_type(BIT(ETS_CPU_INTR0_INUM), INTR_TYPE_LEVEL); - esprv_intc_int_set_priority(ETS_CPU_INTR0_INUM, 1); - - // TODO ESP32-C3 IDF-2126, maybe can use interrupt allocation API for all of the above? unsure... - esp_intr_reserve(ETS_CPU_INTR0_INUM, xPortGetCoreID()); -} - void prvTaskExitError(void) { /* A function that implements a task must not exit or attempt to return to @@ -191,8 +167,7 @@ void prvTaskExitError(void) defined, then stop here so application writers can catch the error. */ configASSERT(uxCriticalNesting == ~0UL); portDISABLE_INTERRUPTS(); - for (;;) - ; + abort(); } /* Clear current interrupt mask and set given mask */ @@ -212,9 +187,6 @@ int vPortSetInterruptMask(void) return ret; } -/* - * See header file for description. - */ StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters) { extern uint32_t __global_pointer$; @@ -231,11 +203,15 @@ StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxC frame->a1 = 0x11111111; frame->a2 = 0x22222222; frame->a3 = 0x33333333; + + //TODO: IDF-2393 return (StackType_t *)frame; } -void vPortSysTickHandler(void) +IRAM_ATTR void vPortSysTickHandler(void *arg) { + (void)arg; + systimer_ll_clear_alarm_int(SYSTIMER_ALARM_0); if (!uxSchedulerRunning) { @@ -243,19 +219,23 @@ void vPortSysTickHandler(void) } if (xTaskIncrementTick() != pdFALSE) { - vTaskSwitchContext(); + vPortYieldFromISR(); } } BaseType_t xPortStartScheduler(void) { - vPortSetupTimer(); - vPortSetupSoftwareInterrupt(); + uxInterruptNesting = 0; uxCriticalNesting = 0; - uxSchedulerRunning = 0; /* this means first yield */ + uxSchedulerRunning = 0; + + vPortSetupTimer(); + esprv_intc_int_set_threshold(1); /* set global INTC masking level */ riscv_global_interrupts_enable(); + vPortYield(); + /*Should not get here*/ return pdFALSE; } @@ -263,21 +243,18 @@ BaseType_t xPortStartScheduler(void) void vPortEndScheduler(void) { /* very unlikely this function will be called, so just trap here */ - while (1) - ; -} - -void vPortSoftwareInterrupt(void) -{ - uxSchedulerRunning = 1; - vTaskSwitchContext(); - REG_WRITE(SYSTEM_CPU_INTR_FROM_CPU_0_REG, 0); + abort(); } void vPortYieldOtherCore(BaseType_t coreid) { - (void)coreid; - vPortYield(); + esp_crosscore_int_send_yield(coreid); +} + +void vPortYieldFromISR( void ) +{ + uxSchedulerRunning = 1; + xPortSwitchFlag = 1; } void vPortYield(void) @@ -285,8 +262,8 @@ void vPortYield(void) if (uxInterruptNesting) { vPortYieldFromISR(); } else { - REG_WRITE(SYSTEM_CPU_INTR_FROM_CPU_0_REG, 1); + 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 @@ -297,13 +274,9 @@ void vPortYield(void) 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) { } + while (uxSchedulerRunning && uxCriticalNesting == 0 && REG_READ(SYSTEM_CPU_INTR_FROM_CPU_0_REG) != 0) {} } -} -void vPortYieldFromISR(void) -{ - vTaskSwitchContext(); } void vPortSetStackWatchpoint(void *pxStackStart) @@ -319,30 +292,30 @@ BaseType_t xPortInIsrContext(void) BaseType_t IRAM_ATTR xPortInterruptedFromISRContext(void) { /* For single core, this can be the same as xPortInIsrContext() because reading it is atomic */ - return uxInterruptNesting; + return uxInterruptNesting; } void vPortCPUInitializeMutex(portMUX_TYPE *mux) { - (void)mux; + (void)mux; //TODO: IDF-2393 } void vPortCPUAcquireMutex(portMUX_TYPE *mux) { - (void)mux; + (void)mux; //TODO: IDF-2393 } bool vPortCPUAcquireMutexTimeout(portMUX_TYPE *mux, int timeout_cycles) { - (void)mux; + (void)mux; //TODO: IDF-2393 (void)timeout_cycles; return true; } void vPortCPUReleaseMutex(portMUX_TYPE *mux) { - (void)mux; + (void)mux; //TODO: IDF-2393 } void __attribute__((weak)) vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName) diff --git a/components/freertos/port/riscv/portasm.S b/components/freertos/port/riscv/portasm.S index e4e05e3d68..d32103f5f8 100644 --- a/components/freertos/port/riscv/portasm.S +++ b/components/freertos/port/riscv/portasm.S @@ -37,14 +37,23 @@ rtos_int_enter: /* scheduler not enabled, jump directly to ISR handler */ lw t0, uxSchedulerRunning - beq t0,zero, not_rtos_enter + beq t0,zero, rtos_enter_end - /* Sabe current TCB and load the ISR stack */ + /* 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, pxCurrentTCB sw t2, 0x0(t0) lw sp, xIsrStackTop -not_rtos_enter: +rtos_enter_end: mv ra, t1 ret @@ -56,10 +65,23 @@ not_rtos_enter: .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, not_rtos_exit + 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 @@ -83,5 +105,5 @@ no_switch: lw a0, pxCurrentTCB lw a0, 0x0(a0) -not_rtos_exit: +rtos_exit_end: ret diff --git a/components/hal/CMakeLists.txt b/components/hal/CMakeLists.txt index e43a4c44f8..57f07b3063 100644 --- a/components/hal/CMakeLists.txt +++ b/components/hal/CMakeLists.txt @@ -28,8 +28,7 @@ if(NOT BOOTLOADER_BUILD) "soc_hal.c" "interrupt_controller_hal.c" "sha_hal.c" - "aes_hal.c" - "${target}/interrupt_descriptor_table.c") + "aes_hal.c") if(${target} STREQUAL "esp32") list(APPEND srcs @@ -43,6 +42,7 @@ if(NOT BOOTLOADER_BUILD) "twai_hal_iram.c" "esp32/adc_hal.c" "esp32/brownout_hal.c" + "esp32/interrupt_descriptor_table.c" "esp32/touch_sensor_hal.c") if(NOT BOOTLOADER_BUILD AND CONFIG_ETH_USE_ESP32_EMAC) list(APPEND srcs "esp32/emac_hal.c") @@ -65,6 +65,7 @@ if(NOT BOOTLOADER_BUILD) "esp32s2/systimer_hal.c" "esp32s2/touch_sensor_hal.c" "esp32s2/dac_hal.c" + "esp32s2/interrupt_descriptor_table.c" "esp32s2/usb_hal.c") endif() @@ -79,6 +80,7 @@ if(NOT BOOTLOADER_BUILD) "twai_hal.c" "twai_hal_iram.c" "esp32s3/brownout_hal.c" + "esp32s3/interrupt_descriptor_table.c" "esp32s3/systimer_hal.c" "esp32s3/touch_sensor_hal.c") endif() diff --git a/components/hal/esp32/include/hal/interrupt_controller_ll.h b/components/hal/esp32/include/hal/interrupt_controller_ll.h index b61fa47dbc..6634b003c4 100644 --- a/components/hal/esp32/include/hal/interrupt_controller_ll.h +++ b/components/hal/esp32/include/hal/interrupt_controller_ll.h @@ -62,7 +62,7 @@ static inline bool intr_cntrl_ll_has_handler(uint8_t intr, uint8_t cpu) * @param handler handler invoked when an interrupt occurs * @param arg optional argument to pass to the handler */ -static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler_t handler, void * arg) +static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler_t handler, void *arg) { xt_set_interrupt_handler(intr, (xt_handler)handler, arg); } @@ -74,7 +74,7 @@ static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler * * @return argument used by handler of passed interrupt number */ -static inline void * intr_cntrl_ll_get_int_handler_arg(uint8_t intr) +static inline void *intr_cntrl_ll_get_int_handler_arg(uint8_t intr) { return xt_get_interrupt_handler_arg(intr); } @@ -100,6 +100,16 @@ static inline void intr_cntrl_ll_enable_int_mask(uint32_t newmask) xt_int_enable_mask(newmask); } +/** + * @brief Acknowledge an edge-trigger interrupt by clearing its pending flag + * + * @param intr interrupt number ranged from 0 to 31 + */ +static inline void intr_cntrl_ll_edge_int_acknowledge(int intr) +{ + xthal_set_intclear(1 << intr); +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32c3/include/hal/cpu_ll.h b/components/hal/esp32c3/include/hal/cpu_ll.h index e819fff803..ce8062c561 100644 --- a/components/hal/esp32c3/include/hal/cpu_ll.h +++ b/components/hal/esp32c3/include/hal/cpu_ll.h @@ -30,7 +30,7 @@ extern "C" { #endif -static inline int cpu_ll_get_core_id(void) +static inline int IRAM_ATTR cpu_ll_get_core_id(void) { #if SOC_CPU_CORES_NUM == 1 return 0; // No need to check core ID on single core hardware diff --git a/components/hal/esp32c3/include/hal/interrupt_controller_ll.h b/components/hal/esp32c3/include/hal/interrupt_controller_ll.h index 96277e9922..1957e0384b 100644 --- a/components/hal/esp32c3/include/hal/interrupt_controller_ll.h +++ b/components/hal/esp32c3/include/hal/interrupt_controller_ll.h @@ -68,7 +68,7 @@ static inline bool intr_cntrl_ll_has_handler(uint8_t intr, uint8_t cpu) * @param handler handler invoked when an interrupt occurs * @param arg optional argument to pass to the handler */ -static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler_t handler, void * arg) +static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler_t handler, void *arg) { intr_handler_set(intr, (void *)handler, arg); } @@ -80,7 +80,7 @@ static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler * * @return argument used by handler of passed interrupt number */ -static inline void * intr_cntrl_ll_get_int_handler_arg(uint8_t intr) +static inline void *intr_cntrl_ll_get_int_handler_arg(uint8_t intr) { return intr_handler_get_arg(intr); } @@ -116,27 +116,36 @@ static inline void intr_cntrl_ll_enable_int_mask(uint32_t newmask) } /** - * @brief Set the interrupt type given an interrupt number. + * @brief Acknowledge an edge-trigger interrupt by clearing its pending flag * - * @param interrupt_number number of the interrupt - * @param type new type for this interrupt + * @param intr interrupt number ranged from 0 to 31 */ -static inline void intr_cntrl_ll_set_type(int interrupt_number, int_type_t type) +static inline void intr_cntrl_ll_edge_int_acknowledge(int intr) { - esprv_intc_int_set_type(BIT(interrupt_number), type); + REG_SET_BIT(INTERRUPT_CORE0_CPU_INT_CLEAR_REG, intr); } /** - * @brief Set the interrupt level (priority) given an interrupt number. + * @brief Sets the interrupt level int the interrupt controller. * - * @param interrupt_number number of the interrupt - * @param level new level for this interrupt + * @param interrupt_number Interrupt number 0 to 31 + * @param level priority between 1 (lowest) to 7 (highest) */ -static inline void intr_cntrl_ll_set_level(int interrupt_number, int level) +static inline void intr_cntrl_ll_set_int_level(int intr, int level) { - esprv_intc_int_set_priority(interrupt_number, level); + esprv_intc_int_set_priority(intr, level); } +/** + * @brief Set the type of an interrupt in the controller. + * + * @param interrupt_number Interrupt number 0 to 31 + * @param type interrupt type as edge or level triggered + */ +static inline void intr_cntrl_ll_set_int_type(int intr, int_type_t type) +{ + esprv_intc_int_set_type(BIT(intr), type); +} #ifdef __cplusplus } diff --git a/components/hal/esp32c3/interrupt_descriptor_table.c b/components/hal/esp32c3/interrupt_descriptor_table.c deleted file mode 100644 index b4c8637b91..0000000000 --- a/components/hal/esp32c3/interrupt_descriptor_table.c +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2020 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#include "sdkconfig.h" -#include "hal/interrupt_controller_hal.h" -#include "soc/soc_caps.h" -#include "soc/soc.h" - -// TODO ESP32-C3 IDF-2126 check this table is correct, some interrupts may be unnecessarily reserved or not reserved -// or marked as the wrong type - -//This is basically a software-readable version of the interrupt usage table in include/soc/soc.h -const int_desc_t interrupt_descriptor_table[32] = { - { 1, INTTP_LEVEL, {INTDESC_RESVD } }, //0 - { 1, INTTP_LEVEL, {INTDESC_SPECIAL } }, //1 - { 1, INTTP_LEVEL, {INTDESC_NORMAL } }, //2 - { 1, INTTP_LEVEL, {INTDESC_NORMAL } }, //3 - { 1, INTTP_LEVEL, {INTDESC_NORMAL } }, //4 - { 1, INTTP_LEVEL, {INTDESC_SPECIAL } }, //5 - { 1, INTTP_NA, {INTDESC_NORMAL } }, //6 - { 1, INTTP_NA, {INTDESC_NORMAL } }, //7 - { 1, INTTP_LEVEL, {INTDESC_SPECIAL } }, //8 - { 1, INTTP_LEVEL, {INTDESC_SPECIAL } }, //9 - { 1, INTTP_EDGE, {INTDESC_NORMAL } }, //10 - { 3, INTTP_NA, {INTDESC_NORMAL } }, //11 - { 1, INTTP_LEVEL, {INTDESC_SPECIAL } }, //12 - { 1, INTTP_LEVEL, {INTDESC_NORMAL } }, //13 - { 7, INTTP_LEVEL, {INTDESC_NORMAL } }, //14 - { 3, INTTP_NA, {INTDESC_NORMAL } }, //15 - { 5, INTTP_NA, {INTDESC_NORMAL } }, //16 - { 1, INTTP_LEVEL, {INTDESC_NORMAL } }, //17 - { 1, INTTP_LEVEL, {INTDESC_NORMAL } }, //18 - { 2, INTTP_LEVEL, {INTDESC_NORMAL } }, //19 - { 2, INTTP_LEVEL, {INTDESC_NORMAL } }, //20 - { 2, INTTP_LEVEL, {INTDESC_NORMAL } }, //21 - { 3, INTTP_EDGE, {INTDESC_NORMAL } }, //22 - { 3, INTTP_LEVEL, {INTDESC_NORMAL } }, //23 - { 4, INTTP_LEVEL, {INTDESC_RESVD } }, //24 - { 4, INTTP_LEVEL, {INTDESC_RESVD } }, //25 - { 5, INTTP_LEVEL, {INTDESC_NORMAL } }, //26 - { 3, INTTP_LEVEL, {INTDESC_NORMAL } }, //27 - { 4, INTTP_EDGE, {INTDESC_NORMAL } }, //28 - { 3, INTTP_NA, {INTDESC_NORMAL } }, //29 - { 4, INTTP_EDGE, {INTDESC_NORMAL } }, //30 - { 5, INTTP_LEVEL, {INTDESC_NORMAL } }, //31 -}; - -const int_desc_t *interrupt_controller_hal_desc_table(void) -{ - return interrupt_descriptor_table; -} diff --git a/components/hal/esp32s2/include/hal/interrupt_controller_ll.h b/components/hal/esp32s2/include/hal/interrupt_controller_ll.h index b61fa47dbc..5c270ec66e 100644 --- a/components/hal/esp32s2/include/hal/interrupt_controller_ll.h +++ b/components/hal/esp32s2/include/hal/interrupt_controller_ll.h @@ -62,7 +62,7 @@ static inline bool intr_cntrl_ll_has_handler(uint8_t intr, uint8_t cpu) * @param handler handler invoked when an interrupt occurs * @param arg optional argument to pass to the handler */ -static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler_t handler, void * arg) +static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler_t handler, void *arg) { xt_set_interrupt_handler(intr, (xt_handler)handler, arg); } @@ -74,7 +74,7 @@ static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler * * @return argument used by handler of passed interrupt number */ -static inline void * intr_cntrl_ll_get_int_handler_arg(uint8_t intr) +static inline void *intr_cntrl_ll_get_int_handler_arg(uint8_t intr) { return xt_get_interrupt_handler_arg(intr); } @@ -100,6 +100,15 @@ static inline void intr_cntrl_ll_enable_int_mask(uint32_t newmask) xt_int_enable_mask(newmask); } +/** + * @brief Acknowledge an edge-trigger interrupt by clearing its pending flag + * + * @param intr interrupt number ranged from 0 to 31 + */ +static inline void intr_cntrl_ll_edge_int_acknowledge (int intr) +{ + xthal_set_intclear(1 << intr); +} #ifdef __cplusplus } #endif diff --git a/components/hal/esp32s3/include/hal/cpu_ll.h b/components/hal/esp32s3/include/hal/cpu_ll.h index f43c65ef34..a7fb19625c 100644 --- a/components/hal/esp32s3/include/hal/cpu_ll.h +++ b/components/hal/esp32s3/include/hal/cpu_ll.h @@ -21,13 +21,14 @@ #include "xtensa/config/specreg.h" #include "xtensa/config/extreg.h" #include "esp_bit_defs.h" +#include "esp_attr.h" #include "xtensa/config/core.h" #ifdef __cplusplus extern "C" { #endif -static inline int cpu_ll_get_core_id(void) +static inline int IRAM_ATTR cpu_ll_get_core_id(void) { uint32_t id; asm volatile ( diff --git a/components/hal/esp32s3/include/hal/interrupt_controller_ll.h b/components/hal/esp32s3/include/hal/interrupt_controller_ll.h index b61fa47dbc..5c270ec66e 100644 --- a/components/hal/esp32s3/include/hal/interrupt_controller_ll.h +++ b/components/hal/esp32s3/include/hal/interrupt_controller_ll.h @@ -62,7 +62,7 @@ static inline bool intr_cntrl_ll_has_handler(uint8_t intr, uint8_t cpu) * @param handler handler invoked when an interrupt occurs * @param arg optional argument to pass to the handler */ -static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler_t handler, void * arg) +static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler_t handler, void *arg) { xt_set_interrupt_handler(intr, (xt_handler)handler, arg); } @@ -74,7 +74,7 @@ static inline void intr_cntrl_ll_set_int_handler(uint8_t intr, interrupt_handler * * @return argument used by handler of passed interrupt number */ -static inline void * intr_cntrl_ll_get_int_handler_arg(uint8_t intr) +static inline void *intr_cntrl_ll_get_int_handler_arg(uint8_t intr) { return xt_get_interrupt_handler_arg(intr); } @@ -100,6 +100,15 @@ static inline void intr_cntrl_ll_enable_int_mask(uint32_t newmask) xt_int_enable_mask(newmask); } +/** + * @brief Acknowledge an edge-trigger interrupt by clearing its pending flag + * + * @param intr interrupt number ranged from 0 to 31 + */ +static inline void intr_cntrl_ll_edge_int_acknowledge (int intr) +{ + xthal_set_intclear(1 << intr); +} #ifdef __cplusplus } #endif diff --git a/components/hal/include/hal/interrupt_controller_hal.h b/components/hal/include/hal/interrupt_controller_hal.h index c0a6d61822..a7c47e6a5c 100644 --- a/components/hal/include/hal/interrupt_controller_hal.h +++ b/components/hal/include/hal/interrupt_controller_hal.h @@ -23,12 +23,14 @@ extern "C" { #endif +#ifndef SOC_CPU_HAS_FLEXIBLE_INTC /** * @brief Gets target platform interrupt descriptor table * * @return Address of interrupt descriptor table */ __attribute__((pure)) const int_desc_t *interrupt_controller_hal_desc_table(void); +#endif /** * @brief Gets the interrupt type given an interrupt number. @@ -55,24 +57,6 @@ __attribute__((pure)) int interrupt_controller_hal_desc_level(int interrupt_num */ __attribute__((pure)) int_desc_flag_t interrupt_controller_hal_desc_flags(int interrupt_number, int cpu_number); -#if SOC_INTERRUPT_LEVEL_CAN_SET -/** - * @brief Set the interrupt level given an interrupt number. - * - * @param interrupt_number number of the interrupt - * @param level new level for this interrupt - */ -void interrupt_controller_hal_set_level(int interrupt_number, int level); - -/** - * @brief Set the interrupt type given an interrupt number. - * - * @param interrupt_number number of the interrupt - * @param type new type for this interrupt - */ -void interrupt_controller_hal_set_type(int interrupt_number, int_type_t type); -#endif - /** * @brief Gets the interrupt type given an interrupt number. * @@ -95,6 +79,30 @@ static inline int interrupt_controller_hal_get_level(int interrupt_number) return interrupt_controller_hal_desc_level(interrupt_number); } +#ifdef SOC_CPU_HAS_FLEXIBLE_INTC +/** + * @brief Set the type of an interrupt in the controller. + * + * @param interrupt_number Interrupt number 0 to 31 + * @param type interrupt type as edge or level triggered + */ +static inline void interrupt_controller_hal_set_int_type(int intr, int_type_t type) +{ + intr_cntrl_ll_set_int_type(intr, type); +} + +/** + * @brief Sets the interrupt level int the interrupt controller. + * + * @param interrupt_number Interrupt number 0 to 31 + * @param level priority between 1 (lowest) to 7 (highest) + */ +static inline void interrupt_controller_hal_set_int_level(int intr, int level) +{ + intr_cntrl_ll_set_int_level(intr, level); +} +#endif + /** * @brief Gets the cpu flags given the interrupt number and target cpu. * @@ -184,6 +192,16 @@ static inline void interrupt_controller_hal_enable_int_mask(uint32_t newmask) intr_cntrl_ll_enable_int_mask(newmask); } +/** + * @brief Acknowledge an edge-trigger interrupt by clearing its pending flag + * + * @param intr interrupt number ranged from 0 to 31 + */ +static inline void interrupt_controller_hal_edge_int_acknowledge(int intr) +{ + intr_cntrl_ll_edge_int_acknowledge(intr); +} + #ifdef __cplusplus } #endif diff --git a/components/hal/include/hal/interrupt_controller_types.h b/components/hal/include/hal/interrupt_controller_types.h index bf9be1fd1f..528b0eb35d 100644 --- a/components/hal/include/hal/interrupt_controller_types.h +++ b/components/hal/include/hal/interrupt_controller_types.h @@ -24,13 +24,13 @@ extern "C" { typedef enum { INTDESC_NORMAL=0, INTDESC_RESVD, - INTDESC_SPECIAL + INTDESC_SPECIAL, } int_desc_flag_t; typedef enum { INTTP_LEVEL=0, INTTP_EDGE, - INTTP_NA + INTTP_NA, } int_type_t; typedef struct { diff --git a/components/hal/interrupt_controller_hal.c b/components/hal/interrupt_controller_hal.c index 0c2d2dae97..93bce347c9 100644 --- a/components/hal/interrupt_controller_hal.c +++ b/components/hal/interrupt_controller_hal.c @@ -14,36 +14,52 @@ #include "hal/interrupt_controller_hal.h" +#if __riscv +#include "riscv/instruction_decode.h" + +static bool is_interrupt_number_reserved(int interrupt_number) +{ + extern int _vector_table; + extern int _interrupt_handler; + const intptr_t pc = (intptr_t)(&_vector_table + interrupt_number); + + /* JAL instructions are relative to the PC there are executed from. */ + const intptr_t destination = pc + riscv_decode_offset_from_jal_instruction(pc); + + return destination != (intptr_t)&_interrupt_handler; +} +#endif + int_type_t interrupt_controller_hal_desc_type(int interrupt_number) { +#ifndef SOC_CPU_HAS_FLEXIBLE_INTC const int_desc_t *int_desc = interrupt_controller_hal_desc_table(); - return(int_desc[interrupt_number].type); + return (int_desc[interrupt_number].type); +#else + return (INTTP_NA); +#endif } int interrupt_controller_hal_desc_level(int interrupt_number) { +#ifndef SOC_CPU_HAS_FLEXIBLE_INTC const int_desc_t *int_desc = interrupt_controller_hal_desc_table(); - return(int_desc[interrupt_number].level); + return (int_desc[interrupt_number].level); +#else + return 1; +#endif } int_desc_flag_t interrupt_controller_hal_desc_flags(int interrupt_number, int cpu_number) { +#ifndef SOC_CPU_HAS_FLEXIBLE_INTC const int_desc_t *int_desc = interrupt_controller_hal_desc_table(); - return(int_desc[interrupt_number].cpuflags[cpu_number]); -} - -#if SOC_INTERRUPT_LEVEL_CAN_SET - -void interrupt_controller_hal_set_level(int interrupt_number, int level) { - intr_cntrl_ll_set_level(interrupt_number, level); -} - + return (int_desc[interrupt_number].cpuflags[cpu_number]); +#else +#if __riscv + return is_interrupt_number_reserved(interrupt_number) ? INTDESC_RESVD : INTDESC_NORMAL; +#else + return INTDESC_NORMAL; #endif - -#if SOC_INTERRUPT_TYPE_CAN_SET - -void interrupt_controller_hal_set_type(int interrupt_number, int_type_t type) { - intr_cntrl_ll_set_type(interrupt_number, type); -} - #endif +} diff --git a/components/riscv/CMakeLists.txt b/components/riscv/CMakeLists.txt index 6d3744d6a7..0290ca9937 100644 --- a/components/riscv/CMakeLists.txt +++ b/components/riscv/CMakeLists.txt @@ -7,6 +7,9 @@ if(BOOTLOADER_BUILD) else() set(priv_requires soc freertos) set(srcs + "expression_with_stack_riscv.c" + "expression_with_stack_riscv_asm.S" + "instruction_decode.c" "interrupt.c" "stdatomic.c" "vectors.S") diff --git a/components/riscv/expression_with_stack_riscv.c b/components/riscv/expression_with_stack_riscv.c new file mode 100644 index 0000000000..28e492ce00 --- /dev/null +++ b/components/riscv/expression_with_stack_riscv.c @@ -0,0 +1,79 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +static portMUX_TYPE shared_stack_spinlock = portMUX_INITIALIZER_UNLOCKED; +static void *current_task_stack = NULL; + +extern void esp_shared_stack_invoke_function(shared_stack_function function, void *stack); + +static StackType_t *esp_switch_stack_setup(StackType_t *stack, size_t stack_size) +{ +#if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK + // TODO ESP32-C3 IDF-2207 + // esp_clear_watchpoint(1); + // uint32_t watchpoint_place = ((uint32_t)stack + 32) & ~0x1f ; +#endif + //We need also to tweak current task stackpointer to avoid erroneous + //stack overflow indication, so fills the stack with freertos known pattern: + memset(stack, 0xa5U, stack_size * sizeof(StackType_t)); + + StaticTask_t *current = (StaticTask_t *)xTaskGetCurrentTaskHandle(); + //Then put the fake stack inside of TCB: + current_task_stack = current->pxDummy6; + current->pxDummy6 = (void *)stack; + + StackType_t *top_of_stack = stack + stack_size; + + //Align stack to a 16byte boundary, as required by CPU specific: + top_of_stack = (StackType_t *)(((UBaseType_t)(top_of_stack - 16) & ~0xf)); + RvExcFrame *adjusted_top_of_stack = (RvExcFrame *) top_of_stack; + adjusted_top_of_stack--; + +#if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK + // TODO ESP32-C3 IDF-2207 + //esp_set_watchpoint(1, (uint8_t *)watchpoint_place, 32, ESP_WATCHPOINT_STORE); +#endif + + return ((StackType_t *)adjusted_top_of_stack); +} + + +void esp_execute_shared_stack_function(SemaphoreHandle_t lock, void *stack, size_t stack_size, shared_stack_function function) +{ + assert(lock); + assert(stack); + assert(stack_size > 0 && stack_size >= CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE); + assert(function); + + xSemaphoreTake(lock, portMAX_DELAY); + portENTER_CRITICAL(&shared_stack_spinlock); + stack = esp_switch_stack_setup(stack, stack_size); + portEXIT_CRITICAL(&shared_stack_spinlock); + + esp_shared_stack_invoke_function(function, stack); + + portENTER_CRITICAL(&shared_stack_spinlock); + StaticTask_t *current = (StaticTask_t *)xTaskGetCurrentTaskHandle(); + + //Restore current task stack: + current->pxDummy6 = (StackType_t *)current_task_stack; + vPortSetStackWatchpoint(current->pxDummy6); + portEXIT_CRITICAL(&shared_stack_spinlock); + + xSemaphoreGive(lock); +} diff --git a/components/riscv/expression_with_stack_riscv_asm.S b/components/riscv/expression_with_stack_riscv_asm.S new file mode 100644 index 0000000000..44ca865315 --- /dev/null +++ b/components/riscv/expression_with_stack_riscv_asm.S @@ -0,0 +1,43 @@ +// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + .section .text + + .global esp_shared_stack_invoke_function + .type esp_shared_stack_invoke_function, @function +esp_shared_stack_invoke_function: + /* save current stack and return address */ + mv t0, sp + mv t1, ra + + /* Set shared stack as new stack pointer */ + mv sp, a1 + + /* store the ra and previous stack pointer in a safe place */ + addi sp,sp,-4 + sw t0, 0(sp) + sw t1, 4(sp) + + /* call the subroutine */ + jalr a0, 0 + + /* gets the ra and stack pointer saved previously */ + lw t0, 0(sp) + lw t1, 4(sp) + addi sp, sp, 4 + + /* restore both ra and real stack pointer of current task */ + mv ra, t1 + mv sp, t0 + ret diff --git a/components/soc/esp32c3/include/soc/int_caps.h b/components/riscv/include/riscv/instruction_decode.h similarity index 68% rename from components/soc/esp32c3/include/soc/int_caps.h rename to components/riscv/include/riscv/instruction_decode.h index c84aa3a564..5625680f82 100644 --- a/components/soc/esp32c3/include/soc/int_caps.h +++ b/components/riscv/include/riscv/instruction_decode.h @@ -3,7 +3,7 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at - +// // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software @@ -14,12 +14,20 @@ #pragma once +#include + #ifdef __cplusplus extern "C" { #endif -#define SOC_INTERRUPT_LEVEL_CAN_SET (1) -#define SOC_INTERRUPT_TYPE_CAN_SET (1) +/** + * @brief Decode the offset value from a RISC-V JAL instruction + * @note This API will abort if the instruction is not JAL formatted. + * + * @param inst_addr Address of JAL instruction + * @return int offset value + */ +int riscv_decode_offset_from_jal_instruction(const intptr_t inst_addr); #ifdef __cplusplus } diff --git a/components/riscv/instruction_decode.c b/components/riscv/instruction_decode.c new file mode 100644 index 0000000000..89abccbbbb --- /dev/null +++ b/components/riscv/instruction_decode.c @@ -0,0 +1,38 @@ +// Copyright 2020 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include "riscv/instruction_decode.h" + +typedef union { + struct { + unsigned int opcode: 7; + unsigned int rd: 5; + int imm_19_12: 8; + int imm_11: 1; + int imm_10_1: 10; + int imm20: 1; + }; + unsigned int inst; +} riscv_jal_intruction_t; + +int riscv_decode_offset_from_jal_instruction(const intptr_t inst_addr) +{ + riscv_jal_intruction_t *jal_inst = (riscv_jal_intruction_t *)inst_addr; + // check if it's a valid JAL instruction + if (jal_inst->opcode != 0x6f && jal_inst->rd != 0) { + abort(); + } + return (jal_inst->imm_10_1 | jal_inst->imm_11 << 10 | jal_inst->imm_19_12 << 11 | jal_inst->imm20 << 19) << 1; +} diff --git a/components/riscv/vectors.S b/components/riscv/vectors.S index d273f3ab17..6580517fa8 100644 --- a/components/riscv/vectors.S +++ b/components/riscv/vectors.S @@ -97,11 +97,8 @@ csrw mepc, t0 .endm - .global vPortYieldFromISR - .global uxInterruptNesting - .global uxSchedulerRunning - .global xIsrStackTop - .global pxCurrentTCB + .global rtos_int_enter + .global rtos_int_exit .global _global_interrupt_handler .section .exception_vectors.text @@ -219,25 +216,11 @@ _interrupt_handler: save_regs save_mepc - /* scheduler not enabled, jump directly to ISR handler */ - lw t0, uxSchedulerRunning - beq t0, zero, already_on_handler + /* Before doing anythig preserve the stack pointer */ + /* It will be saved in current TCB, if needed */ + mv a0, sp + call rtos_int_enter - /* increments the ISR nesting count */ - la t0, uxInterruptNesting - lw t1, 0x0(t0) - addi t2,t1,1 - sw t2, 0x0(t0) - - /* If reached here from another low priority ISR, skip stack pushing to TCB */ - bne t1,zero, already_on_handler - - /* Otherwise, save current sp, and use the isr stack from here */ - lw t0, pxCurrentTCB - sw sp, 0x0(t0) - lw sp, xIsrStackTop - -already_on_handler: /* Before dispatch c handler, restore interrupt to enable nested intr */ csrr s1, mcause csrr s2, mstatus @@ -278,29 +261,13 @@ already_on_handler: sw s3, 0(t0) fence - /* may skip RTOS aware interrupt since scheduler was not started */ - lw t1, uxSchedulerRunning - beq t1,zero, isr_exit + /* Yield to the next task is needed: */ + mv a0, sp + call rtos_int_exit - /* update nesting interrupts counter */ - la t0, uxInterruptNesting - lw t1, 0x0(t0) + /* The next (or current) stack pointer is returned in a0 */ + mv sp, a0 - /* Already zero, protect against underflow */ - beq t1, zero, isr_skip_decrement - addi t1,t1, -1 - sw t1, 0x0(t0) - -isr_skip_decrement: - /* may still have interrupts pending, skip section below and exit */ - bne t1,zero,isr_exit - - /* handled all the ISRs and scheduled the next task, take its stack */ - /* load on sp, then exit. */ - lw sp, pxCurrentTCB - lw sp, 0x0(sp) - -isr_exit: /* restore the rest of the registers */ csrw mcause, s1 csrw mstatus, s2 diff --git a/components/soc/esp32c3/include/soc/cpu_caps.h b/components/soc/esp32c3/include/soc/cpu_caps.h index e8692efc29..2d8a80bcfc 100644 --- a/components/soc/esp32c3/include/soc/cpu_caps.h +++ b/components/soc/esp32c3/include/soc/cpu_caps.h @@ -16,5 +16,6 @@ #define SOC_CPU_BREAKPOINTS_NUM 8 #define SOC_CPU_WATCHPOINTS_NUM 8 +#define SOC_CPU_HAS_FLEXIBLE_INTC 1 #define SOC_CPU_WATCHPOINT_SIZE 0x80000000 // bytes diff --git a/components/soc/esp32c3/include/soc/soc_caps.h b/components/soc/esp32c3/include/soc/soc_caps.h index 51d2d1a8d6..2d112540f4 100644 --- a/components/soc/esp32c3/include/soc/soc_caps.h +++ b/components/soc/esp32c3/include/soc/soc_caps.h @@ -43,7 +43,6 @@ #include "rmt_caps.h" #include "spi_caps.h" #include "uart_caps.h" -#include "int_caps.h" /*-------------------------- TOUCH SENSOR CAPS -------------------------------*/ #define SOC_TOUCH_SENSOR_NUM (0) /*! No touch sensors on ESP32-C3 */