]> granicus.if.org Git - esp-idf/commitdiff
Break out high-level interrupts so a component can override them
authorJeroen Domburg <jeroen@espressif.com>
Tue, 18 Apr 2017 09:14:32 +0000 (17:14 +0800)
committerJeroen Domburg <jeroen@espressif.com>
Fri, 7 Jul 2017 04:51:33 +0000 (12:51 +0800)
components/esp32/component.mk
components/esp32/dport_highint_hdl.S [new file with mode: 0644]
components/esp32/panic_highint_hdl.S [new file with mode: 0644]
components/esp32/test/test_int_wdt.c [new file with mode: 0644]
components/freertos/xtensa_vector_defaults.S [new file with mode: 0644]
components/freertos/xtensa_vectors.S
docs/api-guides/index.rst
docs/hlinterrupts.rst [new file with mode: 0644]

index aef14ab3ccfb2d86f0b6b5c63459476d81d15def..1c520193273f94362dce6733f9b9239e33616319 100644 (file)
@@ -25,12 +25,17 @@ ifndef CONFIG_SPI_FLASH_ROM_DRIVER_PATCH
 LINKER_SCRIPTS += esp32.rom.spiflash.ld
 endif
 
+#ld_include_panic_highint_hdl is added as an undefined symbol because otherwise the 
+#linker will ignore panic_highint_hdl.S as it has no other files depending on any
+#symbols in it.
 COMPONENT_ADD_LDFLAGS := -lesp32 \
                          $(COMPONENT_PATH)/libhal.a \
                          -L$(COMPONENT_PATH)/lib \
                          $(addprefix -l,$(LIBS)) \
                          -L $(COMPONENT_PATH)/ld \
                          -T esp32_out.ld \
+                         -u ld_include_panic_highint_hdl \
+                         -u ld_include_dport_highint_hdl \
                          $(addprefix -T ,$(LINKER_SCRIPTS))
 
 ALL_LIB_FILES := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS))
diff --git a/components/esp32/dport_highint_hdl.S b/components/esp32/dport_highint_hdl.S
new file mode 100644 (file)
index 0000000..f07d298
--- /dev/null
@@ -0,0 +1,93 @@
+#include <xtensa/coreasm.h>
+#include <xtensa/corebits.h>
+#include <xtensa/config/system.h>
+#include <xtensa/simcall.h>
+#include "freertos/xtensa_context.h"
+#include "esp_panic.h"
+#include "sdkconfig.h"
+#include "soc/soc.h"
+#include "soc/dport_reg.h"
+
+
+#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"
+    .global     xt_highint5
+    .type       xt_highint5,@function
+    .align      4
+xt_highint5:
+
+
+    /* 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
+
+
+/* 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_dport_highint_hdl
+ld_include_dport_highint_hdl:
+
diff --git a/components/esp32/panic_highint_hdl.S b/components/esp32/panic_highint_hdl.S
new file mode 100644 (file)
index 0000000..67fd110
--- /dev/null
@@ -0,0 +1,128 @@
+// Copyright 2015-2017 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 <xtensa/coreasm.h>
+#include <xtensa/corebits.h>
+#include <xtensa/config/system.h>
+#include <xtensa/simcall.h>
+#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. We use interrupt level 4 for this.
+*/
+
+    .section .iram1,"ax"
+    .global     xt_highint4
+    .type       xt_highint4,@function
+    .align      4
+xt_highint4:
+
+
+    /* 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<<ETS_CACHEERR_INUM)
+    and     a0, a4, a0
+    wsr     a0, INTENABLE
+    movi    a0, PANIC_RSN_CACHEERR
+    j 9f
+1:
+#if CONFIG_INT_WDT_CHECK_CPU1
+    /* Check if the cause is the app cpu failing to tick.*/
+    movi    a0, int_wdt_app_cpu_ticked
+    l32i    a0, a0, 0
+    bnez    a0, 2f
+    /* It is. Modify cause. */
+    movi    a0,PANIC_RSN_INTWDT_CPU1
+    j 9f
+2:
+#endif
+    /* Set EXCCAUSE to reflect cause of the wdt int trigger */
+    movi    a0,PANIC_RSN_INTWDT_CPU0
+9:
+    /* Found the reason, now save it. */
+    s32i    a0, sp, XT_STK_EXCCAUSE
+
+    /* _xt_context_save seems to save the current a0, but we need the interuptees a0. Fix this. */
+    rsr     a0, EXCSAVE_4                   /* save interruptee's a0 */
+
+    s32i    a0, sp, XT_STK_A0
+
+    /* Set up PS for C, disable all interrupts except NMI and debug, and clear EXCM. */
+    movi    a0, PS_INTLEVEL(5) | PS_UM | PS_WOE
+    wsr     a0, PS
+
+    //Call panic handler
+    mov     a6,sp
+    call4   panicHandler
+
+    call0   _xt_context_restore
+    l32i    a0, sp, XT_STK_PS               /* retrieve interruptee's PS */
+    wsr     a0, PS
+    l32i    a0, sp, XT_STK_PC               /* retrieve interruptee's PC */
+    wsr     a0, EPC_4
+    l32i    a0, sp, XT_STK_A0               /* retrieve interruptee's A0 */
+    l32i    sp, sp, XT_STK_A1               /* remove exception frame */
+    rsync                                   /* ensure PS and EPC written */
+
+    rsr     a0, EXCSAVE_4                   /* restore a0 */
+    rfi     4
+
+
+
+/* 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_panic_highint_hdl
+ld_include_panic_highint_hdl:
+
diff --git a/components/esp32/test/test_int_wdt.c b/components/esp32/test/test_int_wdt.c
new file mode 100644 (file)
index 0000000..80a8462
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ Tests for the interrupt watchdog
+*/
+
+#include <esp_types.h>
+#include <stdio.h>
+#include "rom/ets_sys.h"
+#include "unity.h"
+#include "soc/dport_reg.h"
+#include "soc/io_mux_reg.h"
+#include "esp_intr_alloc.h"
+#include "freertos/FreeRTOS.h"
+
+
+
+TEST_CASE("Int wdt test", "[esp32][ignore]")
+{
+    portENTER_CRITICAL_NESTED();
+    while(1);
+}
diff --git a/components/freertos/xtensa_vector_defaults.S b/components/freertos/xtensa_vector_defaults.S
new file mode 100644 (file)
index 0000000..c800a09
--- /dev/null
@@ -0,0 +1,158 @@
+// Copyright 2015-2017 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 "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 as well as some specialized exceptions. 
+The default behaviour is to just exit the interrupt or call the panic handler on the exceptions
+*/
+
+
+#if XCHAL_HAVE_DEBUG
+    .global    xt_debugexception
+    .weak xt_debugexception
+    .set xt_debugexception, _xt_debugexception
+    .section .iram1,"ax"
+    .type       _xt_debugexception,@function
+    .align      4
+
+_xt_debugexception:
+    movi    a0,PANIC_RSN_DEBUGEXCEPTION
+    wsr     a0,EXCCAUSE
+    call0   _xt_panic                       /* does not return */
+    rsr     a0, EXCSAVE+XCHAL_DEBUGLEVEL
+    rfi     XCHAL_DEBUGLEVEL
+
+#endif /* Debug exception */
+
+
+#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 */
+
index e88957e38e332cd1f20bd9c535c8aee49160fdd0..2846a65d179f2e6880a2736e628f551d47302a9d 100644 (file)
@@ -471,28 +471,10 @@ Debug Exception.
     .section    .DebugExceptionVector.text, "ax"
     .global     _DebugExceptionVector
     .align      4
-
+    .global     xt_debugexception
 _DebugExceptionVector:
-
-    #ifdef XT_SIMULATOR
-    /*
-    In the simulator, let the debugger (if any) handle the debug exception,
-    or simply stop the simulation:
-    */
-    wsr     a2, EXCSAVE+XCHAL_DEBUGLEVEL    /* save a2 where sim expects it */
-    movi    a2, SYS_gdb_enter_sktloop
-    simcall                                 /* have ISS handle debug exc. */
-    #elif 0 /* change condition to 1 to use the HAL minimal debug handler */
-    wsr     a3, EXCSAVE+XCHAL_DEBUGLEVEL
-    movi    a3, xthal_debugexc_defhndlr_nw  /* use default debug handler */
-    jx      a3
-    #else
-    wsr     a0, EXCSAVE+XCHAL_DEBUGLEVEL    /* save original a0 somewhere */
-    movi    a0,PANIC_RSN_DEBUGEXCEPTION
-    wsr     a0,EXCCAUSE
-    call0   _xt_panic                       /* does not return */
-    rfi     XCHAL_DEBUGLEVEL                /* make a0 point here not later */
-    #endif
+    wsr     a0, EXCSAVE+XCHAL_DEBUGLEVEL    /* preserve a0 */
+    call0   xt_debugexception            /* load exception handler */
 
     .end        literal_prefix
 
@@ -1060,9 +1042,6 @@ locking.
 
     /* Co-processor exception occurred outside a thread (not supported). */
 .L_xt_coproc_invalid:
-    #if XCHAL_HAVE_DEBUG
-    break   1, 1                            /* unhandled user exception */
-    #endif
     movi    a0,PANIC_RSN_COPROCEXCEPTION
     wsr     a0,EXCCAUSE
     call0   _xt_panic                       /* not in a thread (invalid) */
@@ -1531,9 +1510,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
@@ -1542,37 +1521,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
@@ -1581,38 +1537,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
@@ -1621,110 +1554,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<<ETS_CACHEERR_INUM)
-    and     a0, a4, a0
-    wsr     a0, INTENABLE
-    movi    a0, PANIC_RSN_CACHEERR
-    j 9f
-1:
-#if CONFIG_INT_WDT_CHECK_CPU1
-    /* Check if the cause is the app cpu failing to tick.*/
-    movi    a0, int_wdt_app_cpu_ticked
-    l32i    a0, a0, 0
-    bnez    a0, 2f
-    /* It is. Modify cause. */
-    movi    a0,PANIC_RSN_INTWDT_CPU1
-    j 9f
-2:
-#endif
-    /* Set EXCCAUSE to reflect cause of the wdt int trigger */
-    movi    a0,PANIC_RSN_INTWDT_CPU0
-9:
-    /* Found the reason, now save it. */
-    s32i    a0, sp, XT_STK_EXCCAUSE
-
-    /* _xt_context_save seems to save the current a0, but we need the interuptees a0. Fix this. */
-    rsr     a0, EXCSAVE_4                   /* save interruptee's a0 */
-
-    s32i    a0, sp, XT_STK_A0
-
-    /* Set up PS for C, disable all interrupts except NMI and debug, and clear EXCM. */
-    movi    a0, PS_INTLEVEL(5) | PS_UM | PS_WOE
-    wsr     a0, PS
-
-    //Call panic handler
-    mov     a6,sp
-    call4   panicHandler
-
-    call0   _xt_context_restore
-    l32i    a0, sp, XT_STK_PS               /* retrieve interruptee's PS */
-    wsr     a0, PS
-    l32i    a0, sp, XT_STK_PC               /* retrieve interruptee's PC */
-    wsr     a0, EPC_4
-    l32i    a0, sp, XT_STK_A0               /* retrieve interruptee's A0 */
-    l32i    sp, sp, XT_STK_A1               /* remove exception frame */
-    rsync                                   /* ensure PS and EPC written */
-
-    rsr     a0, EXCSAVE_4                   /* restore a0 */
-    rfi     4
-
 #endif  /* Level 4 */
 
 #if XCHAL_NUM_INTLEVELS >=5 && XCHAL_EXCM_LEVEL <5 && XCHAL_DEBUGLEVEL !=5
@@ -1733,96 +1571,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 */
 
 #if XCHAL_NUM_INTLEVELS >=6 && XCHAL_EXCM_LEVEL <6 && XCHAL_DEBUGLEVEL !=6
@@ -1831,38 +1588,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
@@ -1871,38 +1605,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 */
 
 
index ea27a63ab5245b01a103290d0a9b89dae2ff6d8b..6b92552c6537858e2ed75aebae46cdc6fef4bd46 100644 (file)
@@ -10,6 +10,7 @@ API Guides
    ESP32 Core Dump <core_dump>
    Partition Tables <partition-tables>
    Flash Encryption <../security/flash-encryption>
+   High Level Interrupts <hlinterrupts>
    Secure Boot <../security/secure-boot>
    Deep Sleep Wake Stubs <deep-sleep-stub>
    ULP Coprocessor <ulp>
diff --git a/docs/hlinterrupts.rst b/docs/hlinterrupts.rst
new file mode 100644 (file)
index 0000000..508c473
--- /dev/null
@@ -0,0 +1,66 @@
+High-Level Interrupts
+=====================
+
+.. toctree::
+   :maxdepth: 1
+
+The Xtensa architecture has support for 32 interrupts, divided over 8 levels, plus an assortment of exceptions. On the ESP32, the interrupt
+mux allows most interrupt sources to be routed to these interrupts using the :doc:`interrupt allocator <api/system/intr_alloc>`. Normally,
+interrupts will be written in C, but ESP-IDF allows high-level interrupts to be written in assembly as well, allowing for very low interrupt
+latencies.
+
+Interrupt Levels
+----------------
+
+===== ================= ====================================================
+Level Symbol            Remark
+===== ================= ====================================================
+1     N/A               Exception and level 0 interrupts. Handled by ESP-IDF
+2-3   N/A               Medium level interrupts. Handled by ESP-IDF
+4     xt_highint4       Normally used by ESP-IDF debug logic
+5     xt_highint5       Free to use
+NMI   xt_nmi            Free to use
+dbg   xt_debugexception Debug exception. Called on e.g. a BREAK instruction.
+===== ================= ====================================================
+
+Using these symbols is done by creating an assembly file (suffix .S) and defining the named symbols, like this::
+
+        .section .iram1,"ax"
+        .global     xt_highint5
+        .type       xt_highint5,@function
+        .align      4
+    xt_highint5:
+        ... your code here
+        rsr     a0, EXCSAVE_5 
+        rfi     5
+
+
+For a real-life example, see the components/esp32/panic_highint_hdl.S file; the panic handler iunterrupt is implemented there.
+
+Notes
+-----
+
+ - Do not call C code from a high-level interrupt; because these interupts still run in critical sections, this can cause crashes.
+   (The panic handler interrupt does call normal C code, but this is OK because there is no intention of returning to the normal code
+   flow afterwards.)
+
+ - Make sure your assembly code gets linked in. If the interrupt handler symbol is the only symbol the rest of the code uses from this
+   file, the linker will take the default ISR instead and not link the assembly file into the final project. To get around this, in the
+   assembly file, define a symbol, like this::
+
+            .global ld_include_my_isr_file
+       ld_include_my_isr_file:
+
+
+(The symbol is called ``ld_include_my_isr_file`` here but can have any arbitrary name not defined anywhere else.) 
+Then, in the component.mk, add this file as an unresolved symbol to the ld command line arguments::
+
+   COMPONENT_ADD_LDFLAGS := -u ld_include_my_isr_file
+
+This should cause the linker to always include a file defining ``ld_include_my_isr_file``, causing the ISR to always be linked in.
+
+ - High-level interrupts can be routed and handled using esp_intr_alloc and associated functions. The handler and handler arguments
+   to esp_intr_alloc must be NULL, however.
+
+ - In theory, medium priority interrupts could also be handled in this way. For now, ESP-IDF does not support this.
+