diff --git a/components/bootloader_support/src/bootloader_random.c b/components/bootloader_support/src/bootloader_random.c index 9f3d602e0..70bd8f8db 100644 --- a/components/bootloader_support/src/bootloader_random.c +++ b/components/bootloader_support/src/bootloader_random.c @@ -25,7 +25,7 @@ #include "esp_system.h" #endif -const char *TAG = "boot_rng"; +static const char *TAG = "boot_rng"; void bootloader_fill_random(void *buffer, size_t length) { diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index 9190fcf9c..563419fcd 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -165,6 +165,13 @@ config SPIRAM_CACHE_WORKAROUND when the cache line needs to be fetched from external RAM and an interrupt occurs. This enables a fix in the compiler that makes sure the specific code that is vulnerable to this will not be emitted. +config SPIRAM_CACHE_WORKAROUND_TEST + bool "Debug: Test workaround by generating a lot of interrupts" + default "n" + help + This setting helps testing the SPIRAM cache workaround. It generates a lot of interrupts so + the bug, if still existing, triggers quicker. + choice MEMMAP_SPIRAM_TYPE prompt "Type of SPI RAM chip in use" default MEMMAP_SPIRAM_TYPE_ESPPSRAM32 diff --git a/components/esp32/component.mk b/components/esp32/component.mk index aef14ab3c..600559772 100644 --- a/components/esp32/component.mk +++ b/components/esp32/component.mk @@ -31,6 +31,8 @@ COMPONENT_ADD_LDFLAGS := -lesp32 \ $(addprefix -l,$(LIBS)) \ -L $(COMPONENT_PATH)/ld \ -T esp32_out.ld \ + -u ld_include_panic_highint_hdl \ + -u ld_include_psram_tst \ $(addprefix -T ,$(LINKER_SCRIPTS)) ALL_LIB_FILES := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS)) diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index 246fc6653..c2a1fcfed 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -64,6 +64,7 @@ #include "esp_app_trace.h" #include "esp_clk.h" #include "trax.h" +#include "esp_psram_tst.h" #include "esp_psram.h" @@ -278,6 +279,10 @@ void start_cpu0_default(void) esp_core_dump_init(); #endif +#if CONFIG_SPIRAM_CACHE_WORKAROUND_TEST + psram_tst_setup(); +#endif + xTaskCreatePinnedToCore(&main_task, "main", ESP_TASK_MAIN_STACK, NULL, ESP_TASK_MAIN_PRIO, NULL, 0); @@ -306,6 +311,9 @@ void start_cpu1_default(void) esp_cache_err_int_init(); esp_crosscore_int_init(); esp_dport_access_int_init(); +#if CONFIG_SPIRAM_CACHE_WORKAROUND_TEST + psram_tst_setup(); +#endif ESP_EARLY_LOGI(TAG, "Starting scheduler on APP CPU."); xPortStartScheduler(); diff --git a/components/esp32/include/esp_psram_tst.h b/components/esp32/include/esp_psram_tst.h new file mode 100644 index 000000000..55372985c --- /dev/null +++ b/components/esp32/include/esp_psram_tst.h @@ -0,0 +1,3 @@ + + +void psram_tst_setup(); diff --git a/components/esp32/panic_highint_hdl.S b/components/esp32/panic_highint_hdl.S new file mode 100644 index 000000000..76e23060f --- /dev/null +++ b/components/esp32/panic_highint_hdl.S @@ -0,0 +1,119 @@ +#include +#include +#include +#include +#include "freertos/xtensa_context.h" +#include "esp_panic.h" +#include "sdkconfig.h" +#include "soc/soc.h" + + +/* +In some situations, the panic handler needs to be invoked even when (low/medium priority) interrupts +are disabled. In that case, we use a high interrupt to panic anyway. This is the high-level interrupt +handler for such a situation. +*/ + + .section .iram1,"ax" + .type xt_highint4,@function + .align 4 +xt_highint4: + + #ifdef XT_INTEXC_HOOKS + /* Call interrupt hook if present to (pre)handle interrupts. */ + movi a0, _xt_intexc_hooks + l32i a0, a0, 4<<2 + beqz a0, 1f +.Ln_xt_highint4_call_hook: + callx0 a0 /* must NOT disturb stack! */ +1: + #endif + + + /* On the ESP32, this level is used for panic events that are detected by hardware and should + also panic when interrupts are disabled. At the moment, these are the interrupt watchdog + as well as the cache invalid access interrupt. (24 and 25) */ + + /* Allocate exception frame and save minimal context. */ + mov a0, sp + addi sp, sp, -XT_STK_FRMSZ + s32i a0, sp, XT_STK_A1 + #if XCHAL_HAVE_WINDOWED + s32e a0, sp, -12 /* for debug backtrace */ + #endif + rsr a0, PS /* save interruptee's PS */ + s32i a0, sp, XT_STK_PS + rsr a0, EPC_4 /* save interruptee's PC */ + s32i a0, sp, XT_STK_PC + #if XCHAL_HAVE_WINDOWED + s32e a0, sp, -16 /* for debug backtrace */ + #endif + s32i a12, sp, XT_STK_A12 /* _xt_context_save requires A12- */ + s32i a13, sp, XT_STK_A13 /* A13 to have already been saved */ + call0 _xt_context_save + + /* Save vaddr into exception frame */ + rsr a0, EXCVADDR + s32i a0, sp, XT_STK_EXCVADDR + + /* Figure out reason, save into EXCCAUSE reg */ + + rsr a0, INTERRUPT + extui a0, a0, ETS_CACHEERR_INUM, 1 /* get cacheerr int bit */ + beqz a0, 1f + /* Kill this interrupt; we cannot reset it. */ + rsr a0, INTENABLE + movi a4, ~(1< +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include +#include "esp_err.h" +#include "esp_intr.h" +#include "esp_attr.h" +#include "esp_freertos_hooks.h" +#include "soc/timer_group_struct.h" +#include "soc/timer_group_reg.h" +#include "driver/timer.h" +#include "xtensa/core-macros.h" + +#if CONFIG_SPIRAM_CACHE_WORKAROUND_TEST + +void psram_tst_setup() { + esp_err_t err; + XTHAL_SET_CCOMPARE(2, XTHAL_GET_CCOUNT()+1000); + err=esp_intr_alloc(ETS_INTERNAL_TIMER2_INTR_SOURCE, ESP_INTR_FLAG_LEVEL5|ESP_INTR_FLAG_IRAM, NULL, NULL, NULL); + assert(err==ESP_OK); +} + +#endif diff --git a/components/esp32/psram_tst_asm.S b/components/esp32/psram_tst_asm.S new file mode 100644 index 000000000..5467d5dc9 --- /dev/null +++ b/components/esp32/psram_tst_asm.S @@ -0,0 +1,36 @@ +#include +#include +#include +#include +#include "esp_panic.h" +#include "sdkconfig.h" +#include "soc/soc.h" + + +#if CONFIG_SPIRAM_CACHE_WORKAROUND_TEST + + .section .iram1,"ax" + .global xt_highint5 + .type xt_highint5,@function + .align 4 +xt_highint5: + + esync + rsr a0, CCOUNT + addi a0, a0, 40 + wsr a0, CCOMPARE2 + esync + +.L_xt_highint5_exit: + rsr a0, EXCSAVE_5 /* restore a0 */ + rfi 5 + + +#endif + +/* The linker has no reason to link in this file; all symbols it exports are already defined + (weakly!) in the default int handler. Define a symbol here so we can use it to have the + linker inspect this anyway. */ + + .global ld_include_psram_tst +ld_include_psram_tst: diff --git a/components/freertos/xtensa_int_alias.S b/components/freertos/xtensa_int_alias.S new file mode 100644 index 000000000..5e121daee --- /dev/null +++ b/components/freertos/xtensa_int_alias.S @@ -0,0 +1,5 @@ + + .global xt_highint5 + .global _xt_highint5 + .weak xt_highint5 + .set xt_highint5, _xt_highint5 diff --git a/components/freertos/xtensa_vector_defaults.S b/components/freertos/xtensa_vector_defaults.S new file mode 100644 index 000000000..4270c06c9 --- /dev/null +++ b/components/freertos/xtensa_vector_defaults.S @@ -0,0 +1,126 @@ + +#include "xtensa_rtos.h" +#include "esp_panic.h" +#include "sdkconfig.h" +#include "soc/soc.h" + +/* +This file contains the default handlers for the high interrupt levels. The default behavious +is to just exit the interrupt. +*/ + +#if XCHAL_NUM_INTLEVELS >=2 && XCHAL_EXCM_LEVEL <2 && XCHAL_DEBUGLEVEL !=2 + .global xt_highint2 + .weak xt_highint2 + .set xt_highint2, _xt_highint2 + .section .iram1,"ax" + .type _xt_highint2,@function + .align 4 +_xt_highint2: + + /* Default handler does nothing; just returns */ + .align 4 +.L_xt_highint2_exit: + rsr a0, EXCSAVE_2 /* restore a0 */ + rfi 2 + +#endif /* Level 2 */ + +#if XCHAL_NUM_INTLEVELS >=3 && XCHAL_EXCM_LEVEL <3 && XCHAL_DEBUGLEVEL !=3 + + .global xt_highint3 + .weak xt_highint3 + .set xt_highint3, _xt_highint3 + .section .iram1,"ax" + .type _xt_highint3,@function + .align 4 +_xt_highint3: + + /* Default handler does nothing; just returns */ + + .align 4 +.L_xt_highint3_exit: + rsr a0, EXCSAVE_3 /* restore a0 */ + rfi 3 + +#endif /* Level 3 */ + +#if XCHAL_NUM_INTLEVELS >=4 && XCHAL_EXCM_LEVEL <4 && XCHAL_DEBUGLEVEL !=4 + + .global xt_highint4 + .weak xt_highint4 + .set xt_highint4, _xt_highint4 + .section .iram1,"ax" + .type _xt_highint4,@function + .align 4 +_xt_highint4: + + /* Default handler does nothing; just returns */ + + .align 4 +.L_xt_highint4_exit: + rsr a0, EXCSAVE_4 /* restore a0 */ + rfi 4 + +#endif /* Level 4 */ + +#if XCHAL_NUM_INTLEVELS >=5 && XCHAL_EXCM_LEVEL <5 && XCHAL_DEBUGLEVEL !=5 + + .global xt_highint5 + .weak xt_highint5 + .set xt_highint5, _xt_highint5 + .section .iram1,"ax" + .type _xt_highint5,@function + .align 4 +_xt_highint5: + + /* Default handler does nothing; just returns */ + + .align 4 +.L_xt_highint5_exit: + rsr a0, EXCSAVE_5 /* restore a0 */ + rfi 5 + + +#endif /* Level 5 */ + +#if XCHAL_NUM_INTLEVELS >=6 && XCHAL_EXCM_LEVEL <6 && XCHAL_DEBUGLEVEL !=6 + + .global _xt_highint6 + .global xt_highint6 + .weak xt_highint6 + .set xt_highint6, _xt_highint6 + .section .iram1,"ax" + .type _xt_highint6,@function + .align 4 +_xt_highint6: + + /* Default handler does nothing; just returns */ + + .align 4 +.L_xt_highint6_exit: + rsr a0, EXCSAVE_6 /* restore a0 */ + rfi 6 + +#endif /* Level 6 */ + +#if XCHAL_HAVE_NMI + + .global _xt_nmi + .global xt_nmi + .weak xt_nmi + .set xt_nmi, _xt_nmi + .section .iram1,"ax" + .type _xt_nmi,@function + .align 4 +_xt_nmi: + + /* Default handler does nothing; just returns */ + + .align 4 +.L_xt_nmi_exit: + rsr a0, EXCSAVE + XCHAL_NMILEVEL /* restore a0 */ + rfi XCHAL_NMILEVEL + +#endif /* NMI */ + diff --git a/components/freertos/xtensa_vectors.S b/components/freertos/xtensa_vectors.S index 507a26806..9f94622aa 100644 --- a/components/freertos/xtensa_vectors.S +++ b/components/freertos/xtensa_vectors.S @@ -1522,9 +1522,9 @@ the minimum necessary before jumping to the handler in the .text section. *******************************************************************************/ /* -Currently only shells for high priority interrupt handlers are provided -here. However a template and example can be found in the Cadence Design Systems tools -documentation: "Microprocessor Programmer's Guide". +These stubs just call xt_highintX/xt_nmi to handle the real interrupt. Please define +these in an external assembly source file. If these symbols are not defined anywhere +else, the defaults in xtensa_vector_defaults.S are used. */ #if XCHAL_NUM_INTLEVELS >=2 && XCHAL_EXCM_LEVEL <2 && XCHAL_DEBUGLEVEL !=2 @@ -1533,37 +1533,14 @@ documentation: "Microprocessor Programmer's Guide". .section .Level2InterruptVector.text, "ax" .global _Level2Vector .type _Level2Vector,@function + .global xt_highint2 .align 4 _Level2Vector: wsr a0, EXCSAVE_2 /* preserve a0 */ - call0 _xt_highint2 /* load interrupt handler */ + call0 xt_highint2 /* load interrupt handler */ .end literal_prefix - .section .iram1,"ax" - .type _xt_highint2,@function - .align 4 -_xt_highint2: - - #ifdef XT_INTEXC_HOOKS - /* Call interrupt hook if present to (pre)handle interrupts. */ - movi a0, _xt_intexc_hooks - l32i a0, a0, 2<<2 - beqz a0, 1f -.Ln_xt_highint2_call_hook: - callx0 a0 /* must NOT disturb stack! */ -1: - #endif - - /* USER_EDIT: - ADD HIGH PRIORITY LEVEL 2 INTERRUPT HANDLER CODE HERE. - */ - - .align 4 -.L_xt_highint2_exit: - rsr a0, EXCSAVE_2 /* restore a0 */ - rfi 2 - #endif /* Level 2 */ #if XCHAL_NUM_INTLEVELS >=3 && XCHAL_EXCM_LEVEL <3 && XCHAL_DEBUGLEVEL !=3 @@ -1572,38 +1549,15 @@ _xt_highint2: .section .Level3InterruptVector.text, "ax" .global _Level3Vector .type _Level3Vector,@function + .global xt_highint3 .align 4 _Level3Vector: wsr a0, EXCSAVE_3 /* preserve a0 */ - call0 _xt_highint3 /* load interrupt handler */ + call0 xt_highint3 /* load interrupt handler */ /* never returns here - call0 is used as a jump (see note at top) */ .end literal_prefix - .section .iram1,"ax" - .type _xt_highint3,@function - .align 4 -_xt_highint3: - - #ifdef XT_INTEXC_HOOKS - /* Call interrupt hook if present to (pre)handle interrupts. */ - movi a0, _xt_intexc_hooks - l32i a0, a0, 3<<2 - beqz a0, 1f -.Ln_xt_highint3_call_hook: - callx0 a0 /* must NOT disturb stack! */ -1: - #endif - - /* USER_EDIT: - ADD HIGH PRIORITY LEVEL 3 INTERRUPT HANDLER CODE HERE. - */ - - .align 4 -.L_xt_highint3_exit: - rsr a0, EXCSAVE_3 /* restore a0 */ - rfi 3 - #endif /* Level 3 */ #if XCHAL_NUM_INTLEVELS >=4 && XCHAL_EXCM_LEVEL <4 && XCHAL_DEBUGLEVEL !=4 @@ -1612,110 +1566,15 @@ _xt_highint3: .section .Level4InterruptVector.text, "ax" .global _Level4Vector .type _Level4Vector,@function + .global xt_highint4 .align 4 _Level4Vector: wsr a0, EXCSAVE_4 /* preserve a0 */ - call0 _xt_highint4 /* load interrupt handler */ + call0 xt_highint4 /* load interrupt handler */ /* never returns here - call0 is used as a jump (see note at top) */ .end literal_prefix - .section .iram1,"ax" - .type _xt_highint4,@function - .align 4 -_xt_highint4: - - #ifdef XT_INTEXC_HOOKS - /* Call interrupt hook if present to (pre)handle interrupts. */ - movi a0, _xt_intexc_hooks - l32i a0, a0, 4<<2 - beqz a0, 1f -.Ln_xt_highint4_call_hook: - callx0 a0 /* must NOT disturb stack! */ -1: - #endif - - - /* On the ESP32, this level is used for panic events that are detected by hardware and should - also panic when interrupts are disabled. At the moment, these are the interrupt watchdog - as well as the cache invalid access interrupt. (24 and 25) */ - - /* Allocate exception frame and save minimal context. */ - mov a0, sp - addi sp, sp, -XT_STK_FRMSZ - s32i a0, sp, XT_STK_A1 - #if XCHAL_HAVE_WINDOWED - s32e a0, sp, -12 /* for debug backtrace */ - #endif - rsr a0, PS /* save interruptee's PS */ - s32i a0, sp, XT_STK_PS - rsr a0, EPC_4 /* save interruptee's PC */ - s32i a0, sp, XT_STK_PC - #if XCHAL_HAVE_WINDOWED - s32e a0, sp, -16 /* for debug backtrace */ - #endif - s32i a12, sp, XT_STK_A12 /* _xt_context_save requires A12- */ - s32i a13, sp, XT_STK_A13 /* A13 to have already been saved */ - call0 _xt_context_save - - /* Save vaddr into exception frame */ - rsr a0, EXCVADDR - s32i a0, sp, XT_STK_EXCVADDR - - /* Figure out reason, save into EXCCAUSE reg */ - - rsr a0, INTERRUPT - extui a0, a0, ETS_CACHEERR_INUM, 1 /* get cacheerr int bit */ - beqz a0, 1f - /* Kill this interrupt; we cannot reset it. */ - rsr a0, INTENABLE - movi a4, ~(1<=5 && XCHAL_EXCM_LEVEL <5 && XCHAL_DEBUGLEVEL !=5 @@ -1724,95 +1583,15 @@ _xt_highint4: .section .Level5InterruptVector.text, "ax" .global _Level5Vector .type _Level5Vector,@function + .global xt_highint5 .align 4 _Level5Vector: wsr a0, EXCSAVE_5 /* preserve a0 */ - call0 _xt_highint5 /* load interrupt handler */ + call0 xt_highint5 /* load interrupt handler */ /* never returns here - call0 is used as a jump (see note at top) */ .end literal_prefix -#define L5_INTR_STACK_SIZE 8 -#define L5_INTR_A2_OFFSET 0 -#define L5_INTR_A3_OFFSET 4 - .data -_l5_intr_stack: - .space L5_INTR_STACK_SIZE - - .section .iram1,"ax" - .type _xt_highint5,@function - .align 4 -_xt_highint5: - - #ifdef XT_INTEXC_HOOKS - /* Call interrupt hook if present to (pre)handle interrupts. */ - movi a0, _xt_intexc_hooks - l32i a0, a0, 5<<2 - beqz a0, 1f -.Ln_xt_highint5_call_hook: - callx0 a0 /* must NOT disturb stack! */ -1: - #endif - - /* This section is for access dport register protection */ - /* Allocate exception frame and save minimal context. */ - /* Because the interrupt cause code have protection that only - allow one cpu enter in L5 interrupt at one time, so - there needn't have two _l5_intr_stack for each cpu */ - - movi a0, _l5_intr_stack - s32i a2, a0, L5_INTR_A2_OFFSET - s32i a3, a0, L5_INTR_A3_OFFSET - - /* Check interrupt */ - rsr a0, INTERRUPT - extui a0, a0, ETS_DPORT_INUM, 1 /* get dport int bit */ - beqz a0, 1f - - /* handle dport interrupt */ - /* get CORE_ID */ - getcoreid a0 - beqz a0, 2f - - /* current cpu is 1 */ - movi a0, DPORT_CPU_INTR_FROM_CPU_3_REG - movi a2, 0 - s32i a2, a0, 0 /* clear intr */ - movi a0, 0 /* other cpu id */ - j 3f -2: - /* current cpu is 0 */ - movi a0, DPORT_CPU_INTR_FROM_CPU_2_REG - movi a2, 0 - s32i a2, a0, 0 /* clear intr */ - movi a0, 1 /* other cpu id */ -3: - /* set and wait flag */ - movi a2, dport_access_start - addx4 a2, a0, a2 - movi a3, 1 - s32i a3, a2, 0 - memw - movi a2, dport_access_end - addx4 a2, a0, a2 -.check_dport_access_end: - l32i a3, a2, 0 - beqz a3, .check_dport_access_end - -1: - movi a0, _l5_intr_stack - l32i a2, a0, L5_INTR_A2_OFFSET - l32i a3, a0, L5_INTR_A3_OFFSET - rsync /* ensure register restored */ - - rsr a0, EXCSAVE_5 /* restore a0 */ - rfi 5 - - - .align 4 -.L_xt_highint5_exit: - rsr a0, EXCSAVE_5 /* restore a0 */ - rfi 5 #endif /* Level 5 */ @@ -1822,38 +1601,15 @@ _xt_highint5: .section .Level6InterruptVector.text, "ax" .global _Level6Vector .type _Level6Vector,@function + .global xt_highint6 .align 4 _Level6Vector: wsr a0, EXCSAVE_6 /* preserve a0 */ - call0 _xt_highint6 /* load interrupt handler */ + call0 xt_highint6 /* load interrupt handler */ /* never returns here - call0 is used as a jump (see note at top) */ .end literal_prefix - .section .iram1,"ax" - .type _xt_highint6,@function - .align 4 -_xt_highint6: - - #ifdef XT_INTEXC_HOOKS - /* Call interrupt hook if present to (pre)handle interrupts. */ - movi a0, _xt_intexc_hooks - l32i a0, a0, 6<<2 - beqz a0, 1f -.Ln_xt_highint6_call_hook: - callx0 a0 /* must NOT disturb stack! */ -1: - #endif - - /* USER_EDIT: - ADD HIGH PRIORITY LEVEL 6 INTERRUPT HANDLER CODE HERE. - */ - - .align 4 -.L_xt_highint6_exit: - rsr a0, EXCSAVE_6 /* restore a0 */ - rfi 6 - #endif /* Level 6 */ #if XCHAL_HAVE_NMI @@ -1862,38 +1618,15 @@ _xt_highint6: .section .NMIExceptionVector.text, "ax" .global _NMIExceptionVector .type _NMIExceptionVector,@function + .global xt_nmi .align 4 _NMIExceptionVector: wsr a0, EXCSAVE + XCHAL_NMILEVEL _ /* preserve a0 */ - call0 _xt_nmi /* load interrupt handler */ + call0 xt_nmi /* load interrupt handler */ /* never returns here - call0 is used as a jump (see note at top) */ .end literal_prefix - .section .iram1,"ax" - .type _xt_nmi,@function - .align 4 -_xt_nmi: - - #ifdef XT_INTEXC_HOOKS - /* Call interrupt hook if present to (pre)handle interrupts. */ - movi a0, _xt_intexc_hooks - l32i a0, a0, XCHAL_NMILEVEL<<2 - beqz a0, 1f -.Ln_xt_nmi_call_hook: - callx0 a0 /* must NOT disturb stack! */ -1: - #endif - - /* USER_EDIT: - ADD HIGH PRIORITY NON-MASKABLE INTERRUPT (NMI) HANDLER CODE HERE. - */ - - .align 4 -.L_xt_nmi_exit: - rsr a0, EXCSAVE + XCHAL_NMILEVEL /* restore a0 */ - rfi XCHAL_NMILEVEL - #endif /* NMI */