فهرست منبع

fix(esp32p4): Fixed interrupt handling to use the CLIC controller

Omar Chebib 2 سال پیش
والد
کامیت
8ca191e4c1
27فایلهای تغییر یافته به همراه821 افزوده شده و 509 حذف شده
  1. 18 5
      components/esp_hw_support/cpu.c
  2. 2 2
      components/esp_hw_support/include/esp_cpu.h
  3. 17 13
      components/esp_hw_support/intr_alloc.c
  4. 6 4
      components/esp_rom/include/esp_rom_sys.h
  5. 1 0
      components/esp_system/ld/esp32c2/sections.ld.in
  6. 1 0
      components/esp_system/ld/esp32c3/sections.ld.in
  7. 1 0
      components/esp_system/ld/esp32c6/sections.ld.in
  8. 1 0
      components/esp_system/ld/esp32h2/sections.ld.in
  9. 2 1
      components/esp_system/ld/esp32p4/sections.ld.in
  10. 11 3
      components/esp_system/port/cpu_start.c
  11. 90 14
      components/esp_system/port/include/private/esp_private/hw_stack_guard.h
  12. 7 7
      components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/portasm.S
  13. 8 1
      components/freertos/FreeRTOS-Kernel/portable/riscv/port.c
  14. 99 108
      components/freertos/FreeRTOS-Kernel/portable/riscv/portasm.S
  15. 6 0
      components/riscv/CMakeLists.txt
  16. 35 0
      components/riscv/include/esp_private/vectors_const.h
  17. 22 1
      components/riscv/include/riscv/interrupt.h
  18. 9 11
      components/riscv/include/riscv/rv_utils.h
  19. 100 87
      components/riscv/interrupt.c
  20. 25 120
      components/riscv/vectors.S
  21. 113 0
      components/riscv/vectors_clic.S
  22. 90 0
      components/riscv/vectors_intc.S
  23. 4 0
      components/soc/esp32p4/include/soc/Kconfig.soc_caps.in
  24. 23 3
      components/soc/esp32p4/include/soc/interrupt_reg.h
  25. 1 1
      components/soc/esp32p4/include/soc/soc.h
  26. 1 0
      components/soc/esp32p4/include/soc/soc_caps.h
  27. 128 128
      components/soc/esp32p4/interrupts.c

+ 18 - 5
components/esp_hw_support/cpu.c

@@ -156,21 +156,32 @@ void esp_cpu_wait_for_intr(void)
 
 #if SOC_CPU_HAS_FLEXIBLE_INTC
 
+
+#if SOC_INT_CLIC_SUPPORTED
+
+static bool is_intr_num_resv(int ext_intr_num) {
+    /* On targets that uses CLIC as the interrupt controller, the first 16 lines (0..15) are reserved for software
+     * interrupts, all the other lines starting from 16 and above can be used by external peripheral.
+     * in the case of this function, the parameter only refers to the external peripheral index, so if
+     * `ext_intr_num` is 0, it refers to interrupt index 16.
+     *
+     * Only interrupt line 6 is reserved at the moment since it is used for disabling interrupts */
+    return ext_intr_num == 6;
+}
+
+#else // !SOC_INT_CLIC_SUPPORTED
+
 static bool is_intr_num_resv(int intr_num)
 {
     // Workaround to reserve interrupt number 1 for Wi-Fi, 5,8 for Bluetooth, 6 for "permanently disabled interrupt"
     // [TODO: IDF-2465]
     uint32_t reserved = BIT(1) | BIT(5) | BIT(6) | BIT(8);
 
-    // int_num 0,3,4,7 are inavaliable for PULP cpu
+    // int_num 0,3,4,7 are unavailable for PULP cpu
 #if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2// TODO: IDF-5728 replace with a better macro name
     reserved |= BIT(0) | BIT(3) | BIT(4) | BIT(7);
 #endif
 
-#if SOC_INT_CLIC_SUPPORTED
-    //TODO: IDF-7795
-    return false;
-#endif
     if (reserved & BIT(intr_num)) {
         return true;
     }
@@ -185,6 +196,8 @@ static bool is_intr_num_resv(int intr_num)
     return destination != (intptr_t)&_interrupt_handler;
 }
 
+#endif // SOC_INT_CLIC_SUPPORTED
+
 void esp_cpu_intr_get_desc(int core_id, int intr_num, esp_cpu_intr_desc_t *intr_desc_ret)
 {
     intr_desc_ret->priority = 1;    //Todo: We should make this -1

+ 2 - 2
components/esp_hw_support/include/esp_cpu.h

@@ -233,7 +233,7 @@ FORCE_INLINE_ATTR void esp_cpu_intr_set_ivt_addr(const void *ivt_addr)
 #endif
 }
 
-#if CONFIG_IDF_TARGET_ESP32P4
+#if SOC_INT_CLIC_SUPPORTED
 //TODO: IDF-7863
 //"MTVT is only implemented in RISC-V arch"
 /**
@@ -245,7 +245,7 @@ FORCE_INLINE_ATTR void esp_cpu_intr_set_mtvt_addr(const void *mtvt_addr)
 {
     rv_utils_set_mtvt((uint32_t)mtvt_addr);
 }
-#endif  //#if CONFIG_IDF_TARGET_ESP32P4
+#endif  //#if SOC_INT_CLIC_SUPPORTED
 
 #if SOC_CPU_HAS_FLEXIBLE_INTC
 /**

+ 17 - 13
components/esp_hw_support/intr_alloc.c

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -30,6 +30,9 @@
 #include "esp_ipc.h"
 #endif
 
+/* For targets that uses a CLIC as their interrupt controller, CPU_INT_LINES_COUNT represents the external interrupts count */
+#define CPU_INT_LINES_COUNT 32
+
 static const char* TAG = "intr_alloc";
 
 #define ETS_INTERNAL_TIMER0_INTR_NO 6
@@ -161,7 +164,7 @@ static vector_desc_t *get_desc_for_int(int intno, int cpu)
     }
 }
 
-//Returns a vector_desc entry for an source, the cpu parameter is used to tell GPIO_INT and GPIO_NMI from different CPUs
+//Returns a vector_desc entry for a source, the cpu parameter is used to tell GPIO_INT and GPIO_NMI from different CPUs
 static vector_desc_t * find_desc_for_source(int source, int cpu)
 {
     vector_desc_t *vd = vector_desc_head;
@@ -326,11 +329,11 @@ static int get_available_int(int flags, int cpu, int force, int source)
     vector_desc_t *vd = find_desc_for_source(source, cpu);
     if (vd) {
         // if existing vd found, don't need to search any more.
-        ALCHLOG("get_avalible_int: existing vd found. intno: %d", vd->intno);
+        ALCHLOG("get_available_int: existing vd found. intno: %d", vd->intno);
         if ( force != -1 && force != vd->intno ) {
-            ALCHLOG("get_avalible_int: intr forced but not matach existing. existing intno: %d, force: %d", vd->intno, force);
+            ALCHLOG("get_available_int: intr forced but does not match existing. existing intno: %d, force: %d", vd->intno, force);
         } else if (!is_vect_desc_usable(vd, flags, cpu, force)) {
-            ALCHLOG("get_avalible_int: existing vd invalid.");
+            ALCHLOG("get_available_int: existing vd invalid.");
         } else {
             best = vd->intno;
         }
@@ -348,14 +351,14 @@ static int get_available_int(int flags, int cpu, int force, int source)
         if (is_vect_desc_usable(vd, flags, cpu, force)) {
             best = vd->intno;
         } else {
-            ALCHLOG("get_avalible_int: forced vd invalid.");
+            ALCHLOG("get_avalaible_int: forced vd invalid.");
         }
         return best;
     }
 
     ALCHLOG("get_free_int: start looking. Current cpu: %d", cpu);
-    //No allocated handlers as well as forced intr, iterate over the 32 possible interrupts
-    for (x = 0; x < 32; x++) {
+    /* No allocated handlers as well as forced intr, iterate over the 32 possible interrupts */
+    for (x = 0; x < CPU_INT_LINES_COUNT; x++) {
         //Grab the vector_desc for this vector.
         vd = find_desc_for_int(x, cpu);
         if (vd == NULL) {
@@ -811,12 +814,13 @@ esp_err_t IRAM_ATTR esp_intr_enable(intr_handle_t handle)
 
 esp_err_t IRAM_ATTR esp_intr_disable(intr_handle_t handle)
 {
-    if (!handle) {
+    if (handle == NULL) {
         return ESP_ERR_INVALID_ARG;
     }
+
     portENTER_CRITICAL_SAFE(&spinlock);
     int source;
-    bool disabled = 1;
+    bool disabled = true;
     if (handle->shared_vector_desc) {
         handle->shared_vector_desc->disabled = 1;
         source=handle->shared_vector_desc->source;
@@ -824,8 +828,8 @@ esp_err_t IRAM_ATTR esp_intr_disable(intr_handle_t handle)
         shared_vector_desc_t *svd = handle->vector_desc->shared_vec_info;
         assert(svd != NULL);
         while(svd) {
-            if (svd->source == source && svd->disabled == 0) {
-                disabled = 0;
+            if (svd->source == source && !svd->disabled) {
+                disabled = false;
                 break;
             }
             svd = svd->next;
@@ -924,7 +928,7 @@ esp_err_t esp_intr_dump(FILE *stream)
     for (int cpu = 0; cpu < cpu_num; ++cpu) {
         fprintf(stream, "CPU %d interrupt status:\n", cpu);
         fprintf(stream, " Int  Level  Type   Status\n");
-        for (int i_num = 0; i_num < 32; ++i_num) {
+        for (int i_num = 0; i_num < CPU_INT_LINES_COUNT; ++i_num) {
             fprintf(stream, " %2d  ", i_num);
             esp_cpu_intr_desc_t intr_desc;
             esp_cpu_intr_get_desc(cpu, i_num, &intr_desc);

+ 6 - 4
components/esp_rom/include/esp_rom_sys.h

@@ -1,5 +1,5 @@
 /*
- * SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2010-2023 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: Apache-2.0
  */
@@ -76,12 +76,14 @@ soc_reset_reason_t esp_rom_get_reset_reason(int cpu_no);
  * Usually there're 4 steps to use an interrupt:
  * 1. Route peripheral interrupt source to CPU. e.g.  esp_rom_route_intr_matrix(0, ETS_WIFI_MAC_INTR_SOURCE, ETS_WMAC_INUM)
  * 2. Set interrupt handler for CPU
- * 3. Enable CPU interupt
+ * 3. Enable CPU interrupt
  * 4. Enable peripheral interrupt
  *
- * @param cpu_core The CPU number, which the peripheral interupt will inform to
+ * @param cpu_core The CPU number, which the peripheral interrupt will inform to
  * @param periph_intr_id The peripheral interrupt source number
- * @param cpu_intr_num The CPU interrupt number
+ * @param cpu_intr_num The CPU (external) interrupt number. On targets that use CLIC as their interrupt controller,
+ *                     this number represents the external interrupt number. For example, passing `cpu_intr_num = i`
+ *                     to this function would in fact bind peripheral source to CPU interrupt `CLIC_EXT_INTR_NUM_OFFSET + i`.
  */
 void esp_rom_route_intr_matrix(int cpu_core, uint32_t periph_intr_id, uint32_t cpu_intr_num);
 

+ 1 - 0
components/esp_system/ld/esp32c2/sections.ld.in

@@ -14,6 +14,7 @@ SECTIONS
     _iram_start = ABSOLUTE(.);
     /* Vectors go to start of IRAM */
     ASSERT(ABSOLUTE(.) % 0x100 == 0, "vector address must be 256 byte aligned");
+    KEEP(*(.exception_vectors_table.text));
     KEEP(*(.exception_vectors.text));
     . = ALIGN(4);
 

+ 1 - 0
components/esp_system/ld/esp32c3/sections.ld.in

@@ -145,6 +145,7 @@ SECTIONS
     _iram_start = ABSOLUTE(.);
     /* Vectors go to start of IRAM */
     ASSERT(ABSOLUTE(.) % 0x100 == 0, "vector address must be 256 byte aligned");
+    KEEP(*(.exception_vectors_table.text));
     KEEP(*(.exception_vectors.text));
     . = ALIGN(4);
 

+ 1 - 0
components/esp_system/ld/esp32c6/sections.ld.in

@@ -147,6 +147,7 @@ SECTIONS
     _iram_start = ABSOLUTE(.);
     /* Vectors go to start of IRAM */
     ASSERT(ABSOLUTE(.) % 0x100 == 0, "vector address must be 256 byte aligned");
+    KEEP(*(.exception_vectors_table.text));
     KEEP(*(.exception_vectors.text));
     . = ALIGN(4);
 

+ 1 - 0
components/esp_system/ld/esp32h2/sections.ld.in

@@ -147,6 +147,7 @@ SECTIONS
     _iram_start = ABSOLUTE(.);
     /* Vectors go to start of IRAM */
     ASSERT(ABSOLUTE(.) % 0x100 == 0, "vector address must be 256 byte aligned");
+    KEEP(*(.exception_vectors_table.text));
     KEEP(*(.exception_vectors.text));
     . = ALIGN(4);
 

+ 2 - 1
components/esp_system/ld/esp32p4/sections.ld.in

@@ -167,7 +167,8 @@ SECTIONS
   {
     _iram_start = ABSOLUTE(.);
     /* Vectors go to start of IRAM */
-    ASSERT(ABSOLUTE(.) % 0x100 == 0, "vector address must be 256 byte aligned");
+    ASSERT(ABSOLUTE(.) % 0x40 == 0, "vector address must be 64 byte aligned");
+    KEEP(*(.exception_vectors_table.text));
     KEEP(*(.exception_vectors.text));
     . = ALIGN(4);
 

+ 11 - 3
components/esp_system/port/cpu_start.c

@@ -150,14 +150,22 @@ static void core_intr_matrix_clear(void)
     for (int i = 0; i < ETS_MAX_INTR_SOURCE; i++) {
 #if CONFIG_IDF_TARGET_ESP32P4
         if (core_id == 0) {
-            REG_WRITE(INTERRUPT_CORE0_LP_RTC_INT_MAP_REG + 4 * i, 0);
+            REG_WRITE(INTERRUPT_CORE0_LP_RTC_INT_MAP_REG + 4 * i, ETS_INVALID_INUM);
         } else {
-            REG_WRITE(INTERRUPT_CORE1_LP_RTC_INT_MAP_REG + 4 * i, 0);
+            REG_WRITE(INTERRUPT_CORE1_LP_RTC_INT_MAP_REG + 4 * i, ETS_INVALID_INUM);
         }
 #else
         esp_rom_route_intr_matrix(core_id, i, ETS_INVALID_INUM);
-#endif
+#endif  // CONFIG_IDF_TARGET_ESP32P4
     }
+
+#if SOC_INT_CLIC_SUPPORTED
+    for (int i = 0; i < 32; i++) {
+        /* Set all the CPU interrupt lines to vectored by default, as it is on other RISC-V targets */
+        esprv_intc_int_set_vectored(i, true);
+    }
+#endif // SOC_INT_CLIC_SUPPORTED
+
 }
 
 #if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE

+ 90 - 14
components/esp_system/port/include/private/esp_private/hw_stack_guard.h

@@ -6,6 +6,7 @@
 #pragma once
 
 #ifndef __ASSEMBLER__
+#include "sdkconfig.h"
 #include <stdbool.h>
 #include <stdint.h>
 
@@ -35,24 +36,99 @@ uint32_t esp_hw_stack_guard_get_pc(void);
 #define ASSIST_DEBUG_CORE_0_SP_MIN_OFFSET    (ASSIST_DEBUG_CORE_0_SP_MIN_REG - ASSIST_DEBUG_CORE_0_INTR_ENA_REG)
 #define ASSIST_DEBUG_CORE_0_SP_MAX_OFFSET    (ASSIST_DEBUG_CORE_0_SP_MAX_REG - ASSIST_DEBUG_CORE_0_INTR_ENA_REG)
 
-.macro ESP_HW_STACK_GUARD_SET_BOUNDS_CPU0
-    lui     t0, ASSIST_DEBUG_CORE_0_INTR_ENA_REG_IMM
-    sw      a0, ASSIST_DEBUG_CORE_0_SP_MIN_OFFSET(t0)
-    sw      a1, ASSIST_DEBUG_CORE_0_SP_MAX_OFFSET(t0)
+.macro ESP_HW_STACK_GUARD_SET_BOUNDS_CPU0 reg1
+    lui     \reg1, ASSIST_DEBUG_CORE_0_INTR_ENA_REG_IMM
+    sw      a0, ASSIST_DEBUG_CORE_0_SP_MIN_OFFSET(\reg1)
+    sw      a1, ASSIST_DEBUG_CORE_0_SP_MAX_OFFSET(\reg1)
 .endm
 
-.macro ESP_HW_STACK_GUARD_MONITOR_STOP_CPU0
-    lui     t0, ASSIST_DEBUG_CORE_0_INTR_ENA_REG_IMM
-    lw      t1, 0(t0)
-    andi    t1, t1, ~ASSIST_DEBUG_SP_SPILL_BITS
-    sw      t1, 0(t0)
+.macro ESP_HW_STACK_GUARD_MONITOR_STOP_CPU0 reg1 reg2
+    lui     \reg1, ASSIST_DEBUG_CORE_0_INTR_ENA_REG_IMM
+    lw      \reg2, 0(\reg1)
+    andi    \reg2, \reg2, ~ASSIST_DEBUG_SP_SPILL_BITS
+    sw      \reg2, 0(\reg1)
 .endm
 
-.macro ESP_HW_STACK_GUARD_MONITOR_START_CPU0
-    lui     t0, ASSIST_DEBUG_CORE_0_INTR_ENA_REG_IMM
-    lw      t1, 0(t0)
-    ori     t1, t1, ASSIST_DEBUG_SP_SPILL_BITS
-    sw      t1, 0(t0)
+.macro ESP_HW_STACK_GUARD_MONITOR_START_CPU0 reg1 reg2
+    lui     \reg1, ASSIST_DEBUG_CORE_0_INTR_ENA_REG_IMM
+    lw      \reg2, 0(\reg1)
+    ori     \reg2, \reg2, ASSIST_DEBUG_SP_SPILL_BITS
+    sw      \reg2, 0(\reg1)
 .endm
 
+
+#if SOC_CPU_CORES_NUM > 1
+
+#define ASSIST_DEBUG_CORE_1_INTR_ENA_REG_IMM (ASSIST_DEBUG_CORE_1_INTR_ENA_REG >> 12)
+#define ASSIST_DEBUG_CORE_1_SP_MIN_OFFSET    (ASSIST_DEBUG_CORE_1_SP_MIN_REG - ASSIST_DEBUG_CORE_1_INTR_ENA_REG)
+#define ASSIST_DEBUG_CORE_1_SP_MAX_OFFSET    (ASSIST_DEBUG_CORE_1_SP_MAX_REG - ASSIST_DEBUG_CORE_1_INTR_ENA_REG)
+
+.macro ESP_HW_STACK_GUARD_SET_BOUNDS_CPU1 reg1
+    lui     \reg1, ASSIST_DEBUG_CORE_1_INTR_ENA_REG_IMM
+    sw      a0, ASSIST_DEBUG_CORE_1_SP_MIN_OFFSET(\reg1)
+    sw      a1, ASSIST_DEBUG_CORE_1_SP_MAX_OFFSET(\reg1)
+.endm
+
+.macro ESP_HW_STACK_GUARD_MONITOR_STOP_CPU1 reg1 reg2
+    lui     \reg1, ASSIST_DEBUG_CORE_1_INTR_ENA_REG_IMM
+    lw      \reg2, 0(\reg1)
+    andi    \reg2, \reg2, ~ASSIST_DEBUG_SP_SPILL_BITS
+    sw      \reg2, 0(\reg1)
+.endm
+
+.macro ESP_HW_STACK_GUARD_MONITOR_START_CPU1 reg1 reg2
+    lui     \reg1, ASSIST_DEBUG_CORE_1_INTR_ENA_REG_IMM
+    lw      \reg2, 0(\reg1)
+    ori     \reg2, \reg2, ASSIST_DEBUG_SP_SPILL_BITS
+    sw      \reg2, 0(\reg1)
+.endm
+
+.macro ESP_HW_STACK_GUARD_SET_BOUNDS_CUR_CORE reg1
+    /* Check the current core ID */
+    csrr \reg1, mhartid
+    beqz \reg1, @1f
+    /* Core 1 */
+    ESP_HW_STACK_GUARD_SET_BOUNDS_CPU1 \reg1
+    j 2f
+1:
+    /* Core 0 */
+    ESP_HW_STACK_GUARD_SET_BOUNDS_CPU0 \reg1
+2:
+.endm
+
+.macro ESP_HW_STACK_GUARD_MONITOR_START_CUR_CORE reg1 reg2
+    /* Check the current core ID */
+    csrr \reg1, mhartid
+    beqz \reg1, @1f
+    /* Core 1 */
+    ESP_HW_STACK_GUARD_MONITOR_START_CPU1 \reg1 \reg2
+    j 2f
+1:
+    /* Core 0 */
+    ESP_HW_STACK_GUARD_MONITOR_START_CPU0 \reg1 \reg2
+2:
+.endm
+
+.macro ESP_HW_STACK_GUARD_MONITOR_STOP_CUR_CORE reg1 reg2
+    /* Check the current core ID */
+    csrr \reg1, mhartid
+    beqz \reg1, @1f
+    /* Core 1 */
+    ESP_HW_STACK_GUARD_MONITOR_STOP_CPU1 \reg1 \reg2
+    j 2f
+1:
+    /* Core 0 */
+    ESP_HW_STACK_GUARD_MONITOR_STOP_CPU0 \reg1 \reg2
+2:
+.endm
+
+#else // SOC_CPU_CORES_NUM <= 1
+
+#define ESP_HW_STACK_GUARD_SET_BOUNDS_CUR_CORE      ESP_HW_STACK_GUARD_SET_BOUNDS_CPU0
+#define ESP_HW_STACK_GUARD_MONITOR_START_CUR_CORE   ESP_HW_STACK_GUARD_MONITOR_START_CPU0
+#define ESP_HW_STACK_GUARD_MONITOR_STOP_CUR_CORE    ESP_HW_STACK_GUARD_MONITOR_STOP_CPU0
+
+#endif // SOC_CPU_CORES_NUM > 1
+
+
 #endif // __ASSEMBLER__

+ 7 - 7
components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/portasm.S

@@ -49,8 +49,8 @@ rtos_int_enter:
 	bne t4,zero, rtos_enter_end
 
 #if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
-    /* esp_hw_stack_guard_monitor_stop(); */
-    ESP_HW_STACK_GUARD_MONITOR_STOP_CPU0
+    /* esp_hw_stack_guard_monitor_stop(); pass the scratch registers */
+    ESP_HW_STACK_GUARD_MONITOR_STOP_CUR_CORE a0 a1
 #endif /* CONFIG_ESP_SYSTEM_HW_STACK_GUARD */
 
     /* Save current TCB and load the ISR stack */
@@ -62,9 +62,9 @@ rtos_int_enter:
     /* esp_hw_stack_guard_set_bounds(xIsrStack, xIsrStackTop); */
     la      a0, xIsrStack
     mv      a1, sp
-    ESP_HW_STACK_GUARD_SET_BOUNDS_CPU0
+    ESP_HW_STACK_GUARD_SET_BOUNDS_CUR_CORE a2
     /* esp_hw_stack_guard_monitor_start(); */
-    ESP_HW_STACK_GUARD_MONITOR_START_CPU0
+    ESP_HW_STACK_GUARD_MONITOR_START_CUR_CORE a0 a1
 #endif /* CONFIG_ESP_SYSTEM_HW_STACK_GUARD */
 
 rtos_enter_end:
@@ -118,7 +118,7 @@ no_switch:
 
 #if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
     /* esp_hw_stack_guard_monitor_stop(); */
-    ESP_HW_STACK_GUARD_MONITOR_STOP_CPU0
+    ESP_HW_STACK_GUARD_MONITOR_STOP_CUR_CORE a0 a1
 #endif /* CONFIG_ESP_SYSTEM_HW_STACK_GUARD */
 
     /* Recover the stack of next task */
@@ -131,9 +131,9 @@ no_switch:
      */
     lw      a0, PORT_OFFSET_PX_STACK(t0)
     lw      a1, PORT_OFFSET_PX_END_OF_STACK(t0)
-    ESP_HW_STACK_GUARD_SET_BOUNDS_CPU0
+    ESP_HW_STACK_GUARD_SET_BOUNDS_CUR_CORE a2
     /* esp_hw_stack_guard_monitor_start(); */
-    ESP_HW_STACK_GUARD_MONITOR_START_CPU0
+    ESP_HW_STACK_GUARD_MONITOR_START_CUR_CORE a0 a1
 #endif /* CONFIG_ESP_SYSTEM_HW_STACK_GUARD */
 
 rtos_exit_end:

+ 8 - 1
components/freertos/FreeRTOS-Kernel/portable/riscv/port.c

@@ -92,6 +92,10 @@ volatile UBaseType_t xPortSwitchFlag[portNUM_PROCESSORS] = {0};
 __attribute__((aligned(16))) StackType_t xIsrStack[portNUM_PROCESSORS][configISR_STACK_SIZE];
 StackType_t *xIsrStackTop[portNUM_PROCESSORS] = {0};
 
+#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
+StackType_t *xIsrStackBottom[portNUM_PROCESSORS] = {0};
+#endif
+
 /* ------------------------------------------------ FreeRTOS Portable --------------------------------------------------
  * - Provides implementation for functions required by FreeRTOS
  * - Declared in portable.h
@@ -107,9 +111,12 @@ BaseType_t xPortStartScheduler(void)
     port_uxCriticalNesting[coreID] = 0;
     port_xSchedulerRunning[coreID] = 0;
 
-    /* Initialize ISR Stack top */
+    /* Initialize ISR Stack(s) */
     for (int i = 0; i < portNUM_PROCESSORS; i++) {
         xIsrStackTop[i] = &xIsrStack[i][0] + (configISR_STACK_SIZE & (~((portPOINTER_SIZE_TYPE)portBYTE_ALIGNMENT_MASK)));
+#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
+        xIsrStackBottom[i] = &xIsrStack[i][0];
+#endif
     }
 
     /* Setup the hardware to generate the tick. */

+ 99 - 108
components/freertos/FreeRTOS-Kernel/portable/riscv/portasm.S

@@ -19,7 +19,7 @@
     .global vTaskSwitchContext
     .global xPortSwitchFlag
 #if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
-    .global xIsrStack
+    .global xIsrStackBottom
     .global port_offset_pxStack
     .global port_offset_pxEndOfStack
     .global esp_hw_stack_guard_monitor_stop
@@ -34,75 +34,73 @@
  * current task stack pointer and places it into the pxCurrentTCB.
  * It then loads the ISR stack into sp.
  * TODO: ISR nesting code improvements ?
+ * In the routines below, let's use a0-a5 registers to let the compiler generate
+ * 16-bit instructions.
  */
-
     .global rtos_int_enter
     .type rtos_int_enter, @function
 rtos_int_enter:
-#if CONFIG_IDF_TARGET_ESP32P4
-    //TODO: IDF-7861
-    /* preserve the return address */
-    mv      t1, ra
-    mv      t2, a0
-#endif
-
-    /* If the scheduler is not enabled, jump directly to the ISR handler */
 #if ( configNUM_CORES > 1 )
-    csrr    t6, mhartid                     /* t6 = coreID */
-    slli    t6, t6, 2                       /* t6 = coreID * 4 */
-    la      t0, port_xSchedulerRunning      /* t0 = &port_xSchedulerRunning */
-    add     t0, t0, t6                      /* t0 = &port_xSchedulerRunning[coreID] */
-    lw      t0, (t0)                        /* t0 = port_xSchedulerRunning[coreID] */
+    csrr    a5, mhartid                     /* a5 = coreID */
+    slli    a5, a5, 2                       /* a5 = coreID * 4 */
+    la      a0, port_xSchedulerRunning      /* a0 = &port_xSchedulerRunning */
+    add     a0, a0, a5                      /* a0 = &port_xSchedulerRunning[coreID] */
+    lw      a0, (a0)                        /* a0 = port_xSchedulerRunning[coreID] */
 #else
-    lw      t0, port_xSchedulerRunning      /* t0 = port_xSchedulerRunning */
-#endif /* (configNUM_CORES > 1) */
-    beq     t0, zero, rtos_int_enter_end    /* if (port_xSchedulerRunning[coreID] == 0) jump to rtos_int_enter_end */
+    lw      a0, port_xSchedulerRunning      /* a0 = port_xSchedulerRunning */
+#endif /* ( configNUM_CORES > 1 ) */
+    beqz    a0, rtos_int_enter_end          /* if (port_xSchedulerRunning[coreID] == 0) jump to rtos_int_enter_end */
 
     /* Increment the ISR nesting count */
-    la      t3, port_uxInterruptNesting     /* t3 = &port_usInterruptNesting */
+    la      a0, port_uxInterruptNesting     /* a0 = &port_uxInterruptNesting */
 #if ( configNUM_CORES > 1 )
-    add     t3, t3, t6                      /* t3 = &port_uxInterruptNesting[coreID] // t6 already contains coreID * 4 */
+    add     a0, a0, a5                      /* a0 = &port_uxInterruptNesting[coreID] // a5 already contains coreID * 4 */
 #endif /* ( configNUM_CORES > 1 ) */
-    lw      t4, 0x0(t3)                     /* t4 = port_uxInterruptNesting[coreID] */
-    addi    t5, t4, 1                       /* t5 = t4 + 1 */
-    sw      t5, 0x0(t3)                     /* port_uxInterruptNesting[coreID] = t5 */
+    lw      a1, 0(a0)                       /* a1 = port_uxInterruptNesting[coreID] */
+    addi    a2, a1, 1                       /* a2 = a1 + 1 */
+    sw      a2, 0(a0)                       /* port_uxInterruptNesting[coreID] = a2 */
 
-    /* If we reached here from another low-prio ISR, i.e, port_uxInterruptNesting[coreID] > 0, then skip stack pushing to TCB */
-    bne     t4, zero, rtos_int_enter_end    /* if (port_uxInterruptNesting[coreID] > 0) jump to rtos_int_enter_end */
+    /* If we reached here from another low-priority ISR, i.e, port_uxInterruptNesting[coreID] > 0, then skip stack pushing to TCB */
+    bnez    a1, rtos_int_enter_end          /* if (port_uxInterruptNesting[coreID] > 0) jump to rtos_int_enter_end */
 
 #if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
-    /* esp_hw_stack_guard_monitor_stop(); */
-    ESP_HW_STACK_GUARD_MONITOR_STOP_CPU0
+    /* esp_hw_stack_guard_monitor_stop(); pass the scratch registers */
+    ESP_HW_STACK_GUARD_MONITOR_STOP_CUR_CORE a0 a1
 #endif /* CONFIG_ESP_SYSTEM_HW_STACK_GUARD */
 
     /* Save the current sp in pxCurrentTCB[coreID] and load the ISR stack on to sp */
 #if ( configNUM_CORES > 1 )
-    la      t0, pxCurrentTCB                /* t0 = &pxCurrentTCB */
-    add     t0, t0, t6                      /* t0 = &pxCurrentTCB[coreID] // t6 already contains coreID * 4 */
-    lw      t0, (t0)                        /* t0 = pxCurrentTCB[coreID] */
-    sw      sp, 0x0(t0)                     /* pxCurrentTCB[coreID] = sp */
-    la      t0, xIsrStackTop                /* t0 = &xIsrStackTop */
-    add     t0, t0, t6                      /* t0 = &xIsrStackTop[coreID] // t6 already contains coreID * 4 */
-    lw      sp, 0x0(t0)                     /* sp = xIsrStackTop[coreID] */
+    la      a0, pxCurrentTCB                /* a0 = &pxCurrentTCB */
+    add     a0, a0, a5                      /* a0 = &pxCurrentTCB[coreID] // a5 already contains coreID * 4 */
+    lw      a0, (a0)                        /* a0 = pxCurrentTCB[coreID] */
+    sw      sp, 0(a0)                       /* pxCurrentTCB[coreID] = sp */
+    la      a0, xIsrStackTop                /* a0 = &xIsrStackTop */
+    add     a0, a0, a5                      /* a0 = &xIsrStackTop[coreID] // a5 already contains coreID * 4 */
+    lw      sp, (a0)                        /* sp = xIsrStackTop[coreID] */
 #else
-    lw      t0, pxCurrentTCB                /* t0 = pxCurrentTCB */
-    sw      sp, 0x0(t0)                     /* pxCurrentTCB = sp */
+    lw      a0, pxCurrentTCB                /* a0 = pxCurrentTCB */
+    sw      sp, 0(a0)                       /* pxCurrentTCB[0] = sp */
     lw      sp, xIsrStackTop                /* sp = xIsrStackTop */
 #endif /* ( configNUM_CORES > 1 ) */
 
 #if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
-    /* esp_hw_stack_guard_set_bounds(xIsrStack, xIsrStackTop); */
-    la      a0, xIsrStack
+    /* Prepare the parameters for esp_hw_stack_guard_set_bounds(xIsrStackBottom, xIsrStackTop); */
+#if ( configNUM_CORES > 1 )
+    /* Load the xIsrStack for the current core and set the new bounds */
+    la      a0, xIsrStackBottom
+    add     a0, a0, a5                      /* a0 = &xIsrStackBottom[coreID] */
+    lw      a0, (a0)                        /* a0 = xIsrStackBottom[coreID] */
+#else
+    lw      a0, xIsrStackBottom
+#endif /* ( configNUM_CORES > 1 ) */
     mv      a1, sp
-    ESP_HW_STACK_GUARD_SET_BOUNDS_CPU0
-    ESP_HW_STACK_GUARD_MONITOR_START_CPU0
+    /* esp_hw_stack_guard_set_bounds(xIsrStackBottom[coreID], xIsrStackTop[coreID]);
+     */
+    ESP_HW_STACK_GUARD_SET_BOUNDS_CUR_CORE a2
+    ESP_HW_STACK_GUARD_MONITOR_START_CUR_CORE a0 a1
 #endif /* CONFIG_ESP_SYSTEM_HW_STACK_GUARD */
 
 rtos_int_enter_end:
-#if CONFIG_IDF_TARGET_ESP32P4
-    //TODO: IDF-7861
-    mv      ra, t1
-#endif
     ret
 
 /**
@@ -111,98 +109,91 @@ rtos_int_enter_end:
     .global rtos_int_exit
     .type rtos_int_exit, @function
 rtos_int_exit:
-
-    /* Skip if the scheduler was not started */
 #if ( configNUM_CORES > 1 )
-    csrr    t1, mhartid                     /* t1 = coreID */
-    slli    t1, t1, 2                       /* t1 = t1 * 4 */
-    la      t0, port_xSchedulerRunning      /* t0 = &port_xSchedulerRunning */
-    add     t0, t0, t1                      /* t0 = &port_xSchedulerRunning[coreID] */
-    lw      t0, (t0)                        /* t0 = port_xSchedulerRunning[coreID] */
+    csrr    a1, mhartid                     /* a1 = coreID */
+    slli    a1, a1, 2                       /* a1 = a1 * 4 */
+    la      a0, port_xSchedulerRunning      /* a0 = &port_xSchedulerRunning */
+    add     a0, a0, a1                      /* a0 = &port_xSchedulerRunning[coreID] */
+    lw      a0, (a0)                        /* a0 = port_xSchedulerRunning[coreID] */
 #else
-    lw      t0, port_xSchedulerRunning      /* t0 = port_xSchedulerRunning */
+    lw      a0, port_xSchedulerRunning      /* a0 = port_xSchedulerRunning */
 #endif /* ( configNUM_CORES > 1 ) */
-    beq     t0, zero, rtos_int_exit_end     /* if (port_uxSchewdulerRunning == 0) jump to rtos_int_exit_end */
+    beqz    a0, rtos_int_exit_end           /* if (port_uxSchewdulerRunning == 0) jump to rtos_int_exit_end */
 
-    /* Decrement interrupt nesting counter */
-    la      t2, port_uxInterruptNesting     /* t2 = &port_uxInterruptNesting */
+    /* Update nesting interrupts counter */
+    la      a0, port_uxInterruptNesting     /* a0 = &port_uxInterruptNesting */
 #if ( configNUM_CORES > 1 )
-    add     t2, t2, t1                      /* t2 = &port_uxInterruptNesting[coreID] // t1 already contains coreID * 4 */
-#endif
-    lw      t3, 0x0(t2)                     /* t3 = port_uxInterruptNesting[coreID] */
+    add     a0, a0, a1                      /* a0 = &port_uxInterruptNesting[coreID] // a1 already contains coreID * 4 */
+#endif /* ( configNUM_CORES > 1 ) */
+    lw      a2, 0(a0)                       /* a2 = port_uxInterruptNesting[coreID] */
 
-    /* If the interrupt nesting counter is already zero, then protect against underflow */
-    beq     t3, zero, isr_skip_decrement    /* if (port_uxInterruptNesting[coreID] == 0) jump to isr_skip_decrement */
-    addi    t3, t3, -1                      /* t3 = t3 - 1 */
-    sw      t3, 0x0(t2)                     /* port_uxInterruptNesting[coreID] = t3 */
+    /* Already zero, protect against underflow */
+    beqz    a2, isr_skip_decrement          /* if (port_uxInterruptNesting[coreID] == 0) jump to isr_skip_decrement */
+    addi    a2, a2, -1                      /* a2 = a2 - 1 */
+    sw      a2, 0(a0)                       /* port_uxInterruptNesting[coreID] = a2 */
+    /* May still have interrupts pending, skip section below and exit */
+    bnez    a2, rtos_int_exit_end
 
 isr_skip_decrement:
+    /* If the CPU reached this label, a2 (uxInterruptNesting) is 0 for sure */
 
-    /* We may still have interrupts pending. Skip the section below and exit */
-    bne     t3, zero, rtos_int_exit_end     /* (if port_uxInterruptNesting[coreID] > 0) jump to rtos_int_exit_end */
-
-    /* Schedule the next task if an yield is pending */
-    la      t0, xPortSwitchFlag             /* t0 = &xPortSwitchFlag */
+    /* Schedule the next task if a yield is pending */
+    la      a0, xPortSwitchFlag             /* a0 = &xPortSwitchFlag */
 #if ( configNUM_CORES > 1 )
-    add     t0, t0, t1                      /* t0 = &xPortSwitchFlag[coreID] // t1 already contains coreID * 4 */
+    add     a0, a0, a1                      /* a0 = &xPortSwitchFlag[coreID] // a1 already contains coreID * 4  */
 #endif /* ( configNUM_CORES > 1 ) */
-    lw      t2, 0x0(t0)                     /* t2 = xPortSwitchFlag[coreID] */
-    beq     t2, zero, no_switch             /* if (xPortSwitchFlag[coreID] == 0) jump to no_switch */
+    lw      a2, 0(a0)                       /* a2 = xPortSwitchFlag[coreID] */
+    beqz    a2, no_switch                   /* if (xPortSwitchFlag[coreID] == 0) jump to no_switch */
 
-    /* Save the return address on the stack and create space on the stack for the c-routine call to schedule
-     * the next task. Stack pointer for RISC-V should always be 16 byte aligned. After the switch, restore
-     * the return address and sp.
-     */
-    addi    sp, sp, -16                     /* sp = sp - 16 */
-    sw      ra, 0(sp)                       /* sp = ra */
-    call    vTaskSwitchContext              /* vTaskSwitchContext() */
-    lw      ra, 0(sp)                       /* ra = sp */
-    addi    sp, sp, 16                      /* sp = sp + 16 */
-
-    /* Clear the switch pending flag */
-    la      t0, xPortSwitchFlag             /* t0 = &xPortSwitchFlag */
+    /* Preserve return address and schedule next task. To speed up the process, instead of allocating stack
+     * space, let's use a callee-saved register: s0. Since the caller is not using it, let's use it. */
+    mv      s0, ra
+    call    vTaskSwitchContext
+    mv      ra, s0
+
+    /* Clears the switch pending flag */
+    la      a0, xPortSwitchFlag             /* a0 = &xPortSwitchFlag */
 #if ( configNUM_CORES > 1 )
-    /* c routine vTaskSwitchContext may change the temp registers, so we read again */
-    csrr    t3, mhartid                     /* t3 = coreID */
-    slli    t3, t3, 2                       /* t3 = t3 * 4 */
-    add     t0, t0, t3                      /* t0 = &xPortSwitchFlag[coreID] */
+    /* C routine vTaskSwitchContext may change the temp registers, so we read again */
+    csrr    a1, mhartid                     /* a1 = coreID */
+    slli    a1, a1, 2                       /* a1 = a1 * 4 */
+    add     a0, a0, a1                      /* a0 = &xPortSwitchFlag[coreID]; */
 #endif /* ( configNUM_CORES > 1 ) */
-    mv      t2, zero                        /* t2 = 0 */
-    sw      t2, 0x0(t0)                     /* xPortSwitchFlag[coreID] = t2 */
+    sw      zero, 0(a0)                     /* xPortSwitchFlag[coreID] = 0; */
 
 no_switch:
 
-#if SOC_INT_CLIC_SUPPORTED
-    /* Recover the stack of next task and prepare to exit */
-    la      a0, pxCurrentTCB                /* a0 = &pxCurrentTCB */
-#if ( configNUM_CORES > 1 )
-    csrr    t3, mhartid                     /* t3 = coreID */
-    slli    t3, t3, 2                       /* t3 = t3 * 4 */
-    add     a0, a0, t3                      /* a0 = &pxCurrentTCB[coreID] */
-#endif /* ( configNUM_CORES > 1 ) */
-    lw      a0, (a0)                        /* a0 = pxCurrentTCB[coreID] */
-    lw      a0, 0x0(a0)                     /* a0 = previous sp */
-#else
 #if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
-    /* esp_hw_stack_guard_monitor_stop(); */
-    ESP_HW_STACK_GUARD_MONITOR_STOP_CPU0
+    /* esp_hw_stack_guard_monitor_stop(); pass the scratch registers */
+    ESP_HW_STACK_GUARD_MONITOR_STOP_CUR_CORE a0 a1
 #endif /* CONFIG_ESP_SYSTEM_HW_STACK_GUARD */
 
+
+#if ( configNUM_CORES > 1 )
+    /* Recover the stack of next task and prepare to exit */
+    csrr    a1, mhartid
+    slli    a1, a1, 2
+    la      a0, pxCurrentTCB                /* a0 = &pxCurrentTCB */
+    add     a0, a0, a1                      /* a0 = &pxCurrentTCB[coreID] */
+    lw      a0, 0(a0)                       /* a0 = pxCurrentTCB[coreID] */
+    lw      sp, 0(a0)                       /* sp = previous sp */
+#else
     /* Recover the stack of next task */
-    lw      t0, pxCurrentTCB
-    lw      sp, 0x0(t0)
+    lw      a0, pxCurrentTCB
+    lw      sp, 0(a0)
+#endif /* ( configNUM_CORES > 1 ) */
+
 
 #if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
     /* esp_hw_stack_guard_set_bounds(pxCurrentTCB[0]->pxStack,
      *                               pxCurrentTCB[0]->pxEndOfStack);
      */
-    lw      a0, PORT_OFFSET_PX_STACK(t0)
-    lw      a1, PORT_OFFSET_PX_END_OF_STACK(t0)
-    ESP_HW_STACK_GUARD_SET_BOUNDS_CPU0
+    lw      a1, PORT_OFFSET_PX_END_OF_STACK(a0)
+    lw      a0, PORT_OFFSET_PX_STACK(a0)
+    ESP_HW_STACK_GUARD_SET_BOUNDS_CUR_CORE a2
     /* esp_hw_stack_guard_monitor_start(); */
-    ESP_HW_STACK_GUARD_MONITOR_START_CPU0
+    ESP_HW_STACK_GUARD_MONITOR_START_CUR_CORE a0 a1
 #endif /* CONFIG_ESP_SYSTEM_HW_STACK_GUARD */
-#endif /* SOC_INT_CLIC_SUPPORTED */
 
 rtos_int_exit_end:
     ret

+ 6 - 0
components/riscv/CMakeLists.txt

@@ -14,6 +14,12 @@ else()
         "instruction_decode.c"
         "interrupt.c"
         "vectors.S")
+
+    if(CONFIG_SOC_INT_CLIC_SUPPORTED)
+        list(APPEND srcs "vectors_clic.S")
+    else()
+        list(APPEND srcs "vectors_intc.S")
+    endif()
 endif()
 
 idf_component_register(SRCS "${srcs}"

+ 35 - 0
components/riscv/include/esp_private/vectors_const.h

@@ -0,0 +1,35 @@
+/*
+ * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#pragma once
+
+
+/**
+ * The interrupt bit in `mcause` register is always bit 31 regardless of the interrupt controller used
+ */
+#define VECTORS_MCAUSE_INTBIT_MASK    (0x80000000)
+
+
+#if SOC_INT_CLIC_SUPPORTED
+
+/* When using the CLIC as their interrupt controller, the `mcause` register contains more information than
+ * the interrupt bit and cause:
+ * MINHV[30]: CPU is fetching vector interrupt entry address or not
+ * MPP[29:28]: MSTATUS.MPP[1:0]
+ * MPIL[23:16]: interrupt level before entering interrupt ISR
+ *
+ * Define the mask that will only keep the cause.
+ */
+#define VECTORS_MCAUSE_REASON_MASK   (0x00000fff)
+
+#else // !if SOC_INT_CLIC_SUPPORTED
+
+/**
+ * For targets that use the former INTC or CLINT/PLIC, the `mcause` shouldn't contain any more information
+ * but let's be safe and keep the 32 possible cause values.
+ */
+#define VECTORS_MCAUSE_REASON_MASK   (0x0000001f)
+
+#endif

+ 22 - 1
components/riscv/include/riscv/interrupt.h

@@ -1,11 +1,13 @@
 /*
- * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
+ * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
  *
  * SPDX-License-Identifier: Apache-2.0
  */
 
 #pragma once
 
+#include <stdbool.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -124,6 +126,25 @@ void esprv_intc_int_set_threshold(int priority_threshold);
  */
 uint32_t esprv_intc_get_interrupt_unmask(void);
 
+/**
+ * @brief Check if the given interrupt is hardware vectored
+ *
+ * @param rv_int_num Interrupt number
+ *
+ * @return true if the interrupt is vectored, false if it is not.
+ */
+bool esprv_intc_int_is_vectored(int rv_int_num);
+
+/**
+ * @brief Set interrupt vectored
+ *
+ * Configure the given interrupt number to hardware vectored or non-vectored.
+ *
+ * @param rv_int_num Interrupt number
+ * @param vectored True to set it to vectored, false to set it to non-vectored
+ */
+void esprv_intc_int_set_vectored(int rv_int_num, bool vectored);
+
 #ifdef __cplusplus
 }
 #endif

+ 9 - 11
components/riscv/include/riscv/rv_utils.h

@@ -133,8 +133,9 @@ FORCE_INLINE_ATTR void rv_utils_intr_disable(uint32_t intr_mask)
     RV_SET_CSR(mstatus, old_mstatus & MSTATUS_MIE);
 }
 
-//TODO: IDF-7795, clic related
-#if (SOC_CPU_CORES_NUM > 1)
+
+#if SOC_INT_CLIC_SUPPORTED
+
 FORCE_INLINE_ATTR void __attribute__((always_inline)) rv_utils_restore_intlevel(uint32_t restoreval)
 {
     REG_SET_FIELD(CLIC_INT_THRESH_REG, CLIC_CPU_INT_THRESH, ((restoreval << (8 - NLBITS))) | 0x1f);
@@ -145,8 +146,10 @@ FORCE_INLINE_ATTR uint32_t __attribute__((always_inline)) rv_utils_set_intlevel(
     uint32_t old_mstatus = RV_CLEAR_CSR(mstatus, MSTATUS_MIE);
     uint32_t old_thresh;
 
-    old_thresh = REG_READ(CLIC_INT_THRESH_REG);
-    old_thresh = old_thresh >> (24 + (8 - NLBITS));
+    old_thresh = REG_GET_FIELD(CLIC_INT_THRESH_REG, CLIC_CPU_INT_THRESH);
+    old_thresh = (old_thresh >> (8 - NLBITS));
+    /* Upper bits should already be 0, but let's be safe and keep NLBITS */
+    old_thresh &= BIT(NLBITS) - 1;
 
     REG_SET_FIELD(CLIC_INT_THRESH_REG, CLIC_CPU_INT_THRESH, ((intlevel << (8 - NLBITS))) | 0x1f);
     /**
@@ -166,19 +169,15 @@ FORCE_INLINE_ATTR uint32_t __attribute__((always_inline)) rv_utils_set_intlevel(
 
 FORCE_INLINE_ATTR uint32_t __attribute__((always_inline)) rv_utils_mask_int_level_lower_than(uint32_t intlevel)
 {
-#if SOC_INT_CLIC_SUPPORTED
     /* CLIC's set interrupt level is inclusive, i.e. it does mask the set level  */
     return rv_utils_set_intlevel(intlevel - 1);
-#else
-    return rv_utils_set_intlevel(intlevel);
-#endif /* SOC_INT_CLIC_SUPPORTED */
 }
 
-#endif  //#if (SOC_CPU_CORES_NUM > 1)
+#endif /* SOC_INT_CLIC_SUPPORTED */
+
 
 FORCE_INLINE_ATTR uint32_t rv_utils_intr_get_enabled_mask(void)
 {
-//TODO: IDF-7795
 #if SOC_INT_CLIC_SUPPORTED
     unsigned intr_ena_mask = 0;
     unsigned intr_num;
@@ -194,7 +193,6 @@ FORCE_INLINE_ATTR uint32_t rv_utils_intr_get_enabled_mask(void)
 
 FORCE_INLINE_ATTR void rv_utils_intr_edge_ack(unsigned int intr_num)
 {
-//TODO: IDF-7795
 #if SOC_INT_CLIC_SUPPORTED
     REG_SET_BIT(CLIC_INT_CTRL_REG(intr_num + CLIC_EXT_INTR_NUM_OFFSET) , CLIC_INT_IP);
 #else

+ 100 - 87
components/riscv/interrupt.c

@@ -14,21 +14,33 @@
 #include "riscv/rv_utils.h"
 
 
-//TODO: IDF-7795, P4, see jira to know what changed and what need to be checked
+#if SOC_INT_CLIC_SUPPORTED
 
+/**
+ * If the target is using the CLIC as the interrupt controller, we have 32 external interrupt lines and 16 internal
+ * lines. Let's consider the internal ones reserved and not mappable to any handler.
+ */
+#define RV_EXTERNAL_INT_COUNT   32
+#define RV_EXTERNAL_INT_OFFSET  (CLIC_EXT_INTR_NUM_OFFSET)
 
-#define RV_INT_COUNT 32
+#else // !SOC_INT_CLIC_SUPPORTED
 
-static inline void assert_valid_rv_int_num(int rv_int_num)
-{
-#if SOC_INT_CLIC_SUPPORTED
-    assert(rv_int_num < RV_INT_COUNT && "Invalid CPU interrupt number");
-#else
-    assert(rv_int_num != 0 && rv_int_num < RV_INT_COUNT && "Invalid CPU interrupt number");
-#endif
-}
+/**
+ * In the case of INTC, all the interrupt lines are dedicated to external peripherals, so the offset is 0.
+ * In the case of PLIC, the reserved interrupts are not contiguous, moreover, they are already marked as
+ * unusable by the interrupt allocator, so the offset can also be 0 here.
+ */
+#define RV_EXTERNAL_INT_COUNT   32
+#define RV_EXTERNAL_INT_OFFSET  0
 
-/*************************** Software interrupt dispatcher ***************************/
+/* Since DR_REG_INTERRUPT_CORE0_BASE is not defined on some single-core targets, use the former
+ * DR_REG_INTERRUPT_BASE macro instead. */
+#ifndef DR_REG_INTERRUPT_CORE0_BASE
+#define DR_REG_INTERRUPT_CORE0_BASE DR_REG_INTERRUPT_BASE
+#endif // DR_REG_INTERRUPT_CORE0_BASE
+
+
+#endif // SOC_INT_CLIC_SUPPORTED
 
 
 typedef struct {
@@ -36,98 +48,78 @@ typedef struct {
     void *arg;
 } intr_handler_item_t;
 
-#if SOC_INT_CLIC_SUPPORTED
-static intr_handler_item_t s_intr_handlers_core0[48];
-static intr_handler_item_t s_intr_handlers_core1[48];
-#else
-static intr_handler_item_t s_intr_handlers[32];
+static intr_handler_item_t s_intr_handlers[SOC_CPU_CORES_NUM][RV_EXTERNAL_INT_COUNT];
+
+
+static inline void assert_valid_rv_int_num(int rv_int_num)
+{
+#if !SOC_INT_CLIC_SUPPORTED
+    assert(rv_int_num != 0 && "Invalid CPU interrupt number");
 #endif
+    assert(rv_int_num < RV_EXTERNAL_INT_COUNT && "Invalid CPU interrupt number");
+}
 
-void intr_handler_set(int int_no, intr_handler_t fn, void *arg)
+
+static intr_handler_item_t* intr_get_item(int int_no)
 {
     assert_valid_rv_int_num(int_no);
 
-#if SOC_INT_CLIC_SUPPORTED
-    if (rv_utils_get_core_id() == 0) {
-        s_intr_handlers_core0[int_no + CLIC_EXT_INTR_NUM_OFFSET] = (intr_handler_item_t) {
-            .handler = fn,
-            .arg = arg,
-        };
-    } else {
-        s_intr_handlers_core1[int_no + CLIC_EXT_INTR_NUM_OFFSET] = (intr_handler_item_t) {
-            .handler = fn,
-            .arg = arg,
-        };
-    }
-#else
-    s_intr_handlers[int_no] = (intr_handler_item_t) {
+    const uint32_t id = rv_utils_get_core_id();
+
+    return &s_intr_handlers[id][int_no];
+}
+
+/*************************** Software interrupt dispatcher ***************************/
+
+void intr_handler_set(int int_no, intr_handler_t fn, void *arg)
+{
+    intr_handler_item_t* item = intr_get_item(int_no);
+
+    *item = (intr_handler_item_t) {
         .handler = fn,
         .arg = arg
     };
-#endif
 }
 
 intr_handler_t intr_handler_get(int rv_int_num)
 {
-#if SOC_INT_CLIC_SUPPORTED
-    if (rv_utils_get_core_id() == 0)
-        return s_intr_handlers_core0[rv_int_num + CLIC_EXT_INTR_NUM_OFFSET].handler;
-    else
-        return s_intr_handlers_core1[rv_int_num + CLIC_EXT_INTR_NUM_OFFSET].handler;
-#else
-    return s_intr_handlers[rv_int_num].handler;
-#endif
+    const intr_handler_item_t* item = intr_get_item(rv_int_num);
+    return item->handler;
 }
 
 void *intr_handler_get_arg(int rv_int_num)
 {
-#if SOC_INT_CLIC_SUPPORTED
-    if (rv_utils_get_core_id() == 0)
-        return s_intr_handlers_core0[rv_int_num + CLIC_EXT_INTR_NUM_OFFSET].arg;
-    else
-        return s_intr_handlers_core1[rv_int_num + CLIC_EXT_INTR_NUM_OFFSET].arg;
-#else
-    return s_intr_handlers[rv_int_num].arg;
-#endif
+    const intr_handler_item_t* item = intr_get_item(rv_int_num);
+    return item->arg;
 }
 
 /* called from vectors.S */
 void _global_interrupt_handler(intptr_t sp, int mcause)
 {
-#if SOC_INT_CLIC_SUPPORTED
-    if (rv_utils_get_core_id() == 0) {
-        intr_handler_item_t it = s_intr_handlers_core0[mcause];
-        if (it.handler) {
-            (*it.handler)(it.arg);
-        }
-    } else {
-        intr_handler_item_t it = s_intr_handlers_core1[mcause];
-        if (it.handler) {
-            (*it.handler)(it.arg);
-        }
-    }
-#else
-    intr_handler_item_t it = s_intr_handlers[mcause];
-    if (it.handler) {
-        (*it.handler)(it.arg);
+    /* mcause contains the interrupt number that triggered the current interrupt, this number
+     * also take into account local/internal interrupt, however, this should not happen in practice,
+     * since we never map any peripheral to those. */
+    assert(mcause >= RV_EXTERNAL_INT_OFFSET && "Interrupt sources must not be mapped to local interrupts");
+    const intr_handler_item_t* item = intr_get_item(mcause - RV_EXTERNAL_INT_OFFSET);
+    if (item->handler) {
+        (*item->handler)(item->arg);
     }
-#endif
 }
 
 /*************************** RISC-V interrupt enable/disable ***************************/
 
 void intr_matrix_route(int intr_src, int intr_num)
 {
-#if !SOC_INT_CLIC_SUPPORTED
-    assert(intr_num != 0);
-
-    REG_WRITE(DR_REG_INTERRUPT_BASE + 4 * intr_src, intr_num);
-#else
-    if (rv_utils_get_core_id() == 0)
-        REG_WRITE(DR_REG_INTERRUPT_CORE0_BASE + 4 * intr_src, intr_num + CLIC_EXT_INTR_NUM_OFFSET);
-    else
-        REG_WRITE(DR_REG_INTERRUPT_CORE1_BASE + 4 * intr_src, intr_num + CLIC_EXT_INTR_NUM_OFFSET);
-#endif
+    assert_valid_rv_int_num(intr_num);
+
+    if (rv_utils_get_core_id() == 0) {
+        REG_WRITE(DR_REG_INTERRUPT_CORE0_BASE + 4 * intr_src, intr_num + RV_EXTERNAL_INT_OFFSET);
+    }
+#if SOC_CPU_CORES_NUM > 1
+    else {
+        REG_WRITE(DR_REG_INTERRUPT_CORE1_BASE + 4 * intr_src, intr_num + RV_EXTERNAL_INT_OFFSET);
+    }
+#endif // SOC_CPU_CORES_NUM > 1
 }
 
 // CLIC for each interrupt line provides a IE register
@@ -141,29 +133,50 @@ uint32_t esprv_intc_get_interrupt_unmask(void)
 
 /*************************** ESP-RV Interrupt Controller ***************************/
 
-enum intr_type esprv_intc_int_get_type(int intr_num)
-{
+
 #if SOC_INT_CLIC_SUPPORTED
-    uint32_t intr_type_reg = REG_GET_FIELD(CLIC_INT_CTRL_REG(intr_num + CLIC_EXT_INTR_NUM_OFFSET), CLIC_INT_ATTR_TRIG);
+
+enum intr_type esprv_intc_int_get_type(int rv_int_num)
+{
+    uint32_t intr_type_reg = REG_GET_FIELD(CLIC_INT_CTRL_REG(rv_int_num + RV_EXTERNAL_INT_OFFSET), CLIC_INT_ATTR_TRIG);
     return (intr_type_reg & 1) ? INTR_TYPE_EDGE : INTR_TYPE_LEVEL;
-    // May also support rising edge and falling edge.
-#else
-    uint32_t intr_type_reg = REG_READ(INTERRUPT_CORE0_CPU_INT_TYPE_REG);
-    return (intr_type_reg & (1 << intr_num)) ? INTR_TYPE_EDGE : INTR_TYPE_LEVEL;
-#endif
 }
 
 int esprv_intc_int_get_priority(int rv_int_num)
 {
-#if SOC_INT_CLIC_SUPPORTED
-    uint32_t intr_priority_reg = REG_GET_FIELD(CLIC_INT_CTRL_REG(rv_int_num + CLIC_EXT_INTR_NUM_OFFSET), CLIC_INT_CTL);
+    uint32_t intr_priority_reg = REG_GET_FIELD(CLIC_INT_CTRL_REG(rv_int_num + RV_EXTERNAL_INT_OFFSET), CLIC_INT_CTL);
     return (intr_priority_reg >> (8 - NLBITS));
-#else
+}
+
+
+bool esprv_intc_int_is_vectored(int rv_int_num)
+{
+    const uint32_t shv = REG_GET_FIELD(CLIC_INT_CTRL_REG(rv_int_num + RV_EXTERNAL_INT_OFFSET), CLIC_INT_ATTR_SHV);
+    return shv != 0;
+}
+
+void esprv_intc_int_set_vectored(int rv_int_num, bool vectored)
+{
+    REG_SET_FIELD(CLIC_INT_CTRL_REG(rv_int_num + RV_EXTERNAL_INT_OFFSET), CLIC_INT_ATTR_SHV, vectored ? 1 : 0);
+}
+
+
+#else // !SOC_INT_CLIC_SUPPORTED
+
+enum intr_type esprv_intc_int_get_type(int rv_int_num)
+{
+    uint32_t intr_type_reg = REG_READ(INTERRUPT_CORE0_CPU_INT_TYPE_REG);
+    return (intr_type_reg & (1 << rv_int_num)) ? INTR_TYPE_EDGE : INTR_TYPE_LEVEL;
+}
+
+int esprv_intc_int_get_priority(int rv_int_num)
+{
     uint32_t intr_priority_reg = REG_READ(INTC_INT_PRIO_REG(rv_int_num));
     return intr_priority_reg;
-#endif
 }
 
+#endif // SOC_INT_CLIC_SUPPORTED
+
 /*************************** Exception names. Used in .gdbinit file. ***************************/
 
 const char *riscv_excp_names[16] __attribute__((used)) = {

+ 25 - 120
components/riscv/vectors.S

@@ -9,6 +9,7 @@
 #include "riscv/rvruntime-frames.h"
 #include "soc/soc_caps.h"
 #include "sdkconfig.h"
+#include "esp_private/vectors_const.h"
 
 
     .equ SAVE_REGS, 32
@@ -60,7 +61,7 @@
 
 /* Restore the general purpose registers (excluding gp) from the context on
  * the stack. The context is then deallocated. The default size is CONTEXT_SIZE
- * but it can be overriden. */
+ * but it can be overridden. */
 .macro restore_general_regs cxt_size=CONTEXT_SIZE
     lw   ra, RV_STK_RA(sp)
     lw   tp, RV_STK_TP(sp)
@@ -107,92 +108,10 @@
 #endif
 
     .section .exception_vectors.text
-    /* This is the vector table. MTVEC points here.
-     *
-     * Use 4-byte intructions here. 1 instruction = 1 entry of the table.
-     * The CPU jumps to MTVEC (i.e. the first entry) in case of an exception,
-     * and (MTVEC & 0xfffffffc) + (mcause & 0x7fffffff) * 4, in case of an interrupt.
-     *
-     * Note: for our CPU, we need to place this on a 256-byte boundary, as CPU
-     * only uses the 24 MSBs of the MTVEC, i.e. (MTVEC & 0xffffff00).
-     */
-
-     /**
-      * TODO: IDF-7863, P4, see jira to know what changed and what need to be checked
-      */
-
-#if SOC_INT_CLIC_SUPPORTED
-    .balign 0x40
-#else
-    .balign 0x100
-#endif
-    .global _vector_table
-    .type _vector_table, @function
-_vector_table:
-    .option push
-    .option norvc
-#if SOC_INT_CLIC_SUPPORTED
-    j _trap_handler
-#else
-    j _panic_handler			/* exception handler, entry 0 */
-#if ETS_INT_WDT_INUM != 24
-    #error "ETS_INT_WDT_INUM expected to be 24"
-#endif
-    .rept (ETS_INT_WDT_INUM - 1)
-    j _interrupt_handler		/* 23 identical entries, all pointing to the interrupt handler */
-    .endr
-    j _panic_handler			/* 24: ETS_INT_WDT_INUM panic-interrupt (soc-level panic) */
-    j _panic_handler			/* 25: ETS_CACHEERR_INUM panic-interrupt (soc-level panic) */
-#if CONFIG_ESP_SYSTEM_MEMPROT_FEATURE
-    j _panic_handler			/* 26: ETS_MEMPROT_ERR_INUM panic-interrupt (soc-level panic) */
-#else
-    j _interrupt_handler		/* 26: interrupt-handler */
-#endif // CONFIG_ESP_SYSTEM_MEMPROT_FEATURE
-#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
-    j _panic_handler			/* 27: ETS_ASSIST_DEBUG_INUM panic-interrupt (soc-level panic) */
-#else
-    j _interrupt_handler		/* 27: interrupt-handler */
-#endif // CONFIG_ESP_SYSTEM_HW_STACK_GUARD
-    .rept (ETS_MAX_INUM - ETS_ASSIST_DEBUG_INUM)
-    j _interrupt_handler		/* remain entries are identical, all pointing to the interrupt handler */
-    .endr
-#endif
-    .option pop
-    .size _vector_table, .-_vector_table
-
-#if SOC_INT_CLIC_SUPPORTED
-    .balign 0x40
-    .global _mtvt_table
-    .type _mtvt_table, @function
-_mtvt_table:
-    .option push
-    .option norvc
-    .rept 48
-    .word _interrupt_handler
-    .endr
-    .option pop
-    .size _mtvt_table, .-_mtvt_table
-#endif
-
-#if SOC_INT_CLIC_SUPPORTED
-    .type _trap_handler, @function
-_trap_handler:
-    addi sp, sp, -RV_STK_FRMSZ
-    sw   t0, RV_STK_T0(sp)
-    sw   t1, RV_STK_T1(sp)
-    csrr t0, mcause
-    li t1, 0x80000000
-    bltu t0, t1, _panic_handler
-    lw   t0, RV_STK_T0(sp)
-    lw   t1, RV_STK_T1(sp)
-    addi sp, sp, RV_STK_FRMSZ
-    //ESP32P4-TODO: ETS_T1_WDT_INUM/ETS_CACHEERR_INUM/ETS_MEMPROT_ERR_INUM
-    j _interrupt_handler
-    .size _trap_handler, .-_trap_handler
-#endif
 
     /* Exception handler.*/
     .type _panic_handler, @function
+    .global _panic_handler
 _panic_handler:
     /* Allocate space on the stack and store general purpose registers */
     save_general_regs RV_STK_FRMSZ
@@ -224,16 +143,11 @@ _panic_handler:
     mv    a0, sp
     csrr  a1, mcause
 
-    /*
-     * MINHV[30]: CPU is fetching vector interrupt entry address or not
-     * MPP[29:28]: MSTATUS.MPP[1:0]
-     * MPIL[23:16]: interrupt level before entrering interrupt isr
-     */
-#if SOC_INT_CLIC_SUPPORTED
-    la t1, 0x80000fff
+    /* Only keep the interrupt bit and the source cause of the trap */
+    li t1, VECTORS_MCAUSE_INTBIT_MASK | VECTORS_MCAUSE_REASON_MASK
     and a1, a1, t1
-#endif
-    /* Branches instructions don't accept immediates values, so use t1 to
+
+    /* Branches instructions don't accept immediate values, so use t1 to
      * store our comparator */
     li    t0, 0x80000000
     bgeu  a1, t0, _call_panic_handler
@@ -258,6 +172,10 @@ _call_panic_handler:
      * structure */
     not   t0, t0
     and   a1, a1, t0
+#if CONFIG_SOC_INT_CLIC_SUPPORTED
+    /* When CLIC is supported, external interrupts are shifted by 16, deduct this difference from mcause */
+    add a1, a1, -16
+#endif // CONFIG_SOC_INT_CLIC_SUPPORTED
     sw    a1, RV_STK_MCAUSE(sp)
     jal panic_from_isr
 
@@ -275,6 +193,7 @@ _return_from_exception:
     mret
     .size  _panic_handler, .-_panic_handler
 
+
     /* This is the interrupt handler.
      * It saves the registers on the stack,
      * prepares for interrupt nesting,
@@ -300,12 +219,8 @@ _interrupt_handler:
     /* Save SP */
     sw    t0, RV_STK_SP(sp)
 
-#if CONFIG_IDF_TARGET_ESP32P4
-    //TODO: IDF-7861
-    /* Before doing anythig preserve the stack pointer */
-    /* It will be saved in current TCB, if needed */
-    mv      a0, sp
-#endif  //#if CONFIG_IDF_TARGET_ESP32P4
+    /* Notify the RTOS that an interrupt ocurred, it will save the current stack pointer
+     * in the running TCB, no need to pass it as a parameter */
     call    rtos_int_enter
     /* If this is a non-nested interrupt, SP now points to the interrupt stack */
 
@@ -313,13 +228,13 @@ _interrupt_handler:
     csrr    s1, mcause
     csrr    s2, mstatus
 
-#if !SOC_INT_CLIC_SUPPORTED
+#if !SOC_INT_HW_NESTED_SUPPORTED
     /* Save the interrupt threshold level */
     li      t0, INTERRUPT_CORE0_CPU_INT_THRESH_REG
     lw      s3, 0(t0)
 
     /* Increase interrupt threshold level */
-    li      t2, 0x7fffffff
+    li      t2, VECTORS_MCAUSE_REASON_MASK
     and     t1, s1, t2       /* t1 = mcause & mask */
     slli    t1, t1, 2        /* t1 = mcause * 4 */
     li      t2, INTC_INT_PRIO_REG(0)
@@ -328,7 +243,7 @@ _interrupt_handler:
     addi    t2, t2, 1        /* t2 = t2 +1 */
     sw      t2, 0(t0)        /* INTERRUPT_CORE0_CPU_INT_THRESH_REG = t2 */
     fence
-#endif
+#endif // !SOC_INT_HW_NESTED_SUPPORTED
 
     li      t0, 0x8
     csrrs   t0, mstatus, t0
@@ -354,11 +269,7 @@ _interrupt_handler:
     mv      a0, sp      /* argument 1, stack pointer */
     mv      a1, s1      /* argument 2, interrupt number (mcause) */
     /* mask off the interrupt flag of mcause */
-#if !SOC_INT_CLIC_SUPPORTED
-    li	    t0, 0x7fffffff
-#else
-    li      t0, 0x00000fff
-#endif
+    li	    t0, VECTORS_MCAUSE_REASON_MASK
     and     a1, a1, t0
     jal     _global_interrupt_handler
 
@@ -368,26 +279,20 @@ _interrupt_handler:
     csrrc   t0, mstatus, t0
     /* MIE cleared. Nested interrupts are disabled */
 
-#if !SOC_INT_CLIC_SUPPORTED
+#if !SOC_INT_HW_NESTED_SUPPORTED
     /* restore the interrupt threshold level */
     li      t0, INTERRUPT_CORE0_CPU_INT_THRESH_REG
     sw      s3, 0(t0)
     fence
-#endif
+#endif // !SOC_INT_HW_NESTED_SUPPORTED
 
-#if SOC_INT_CLIC_SUPPORTED
-    /* Yield to the next task is needed: */
-    mv      a0, sp
-#endif
+    /* The RTOS will restore the current TCB stack pointer. This routine will preserve s1 and s2 but alter s0. */
     call    rtos_int_exit
 
-#if CONFIG_IDF_TARGET_ESP32P4
-    //TODO: IDF-7861
-    /* The next (or current) stack pointer is returned in a0 */
-    mv      sp, a0
-#endif  //#if CONFIG_IDF_TARGET_ESP32P4
-
-    /* restore the rest of the registers */
+    /* Restore the rest of the registers.
+     * In case the target uses the CLIC, it is mandatory to restore `mcause` register since it contains
+     * the former CPU priority. When executing `mret`, the hardware will restore the former threshold,
+     * from `mcause` to `mintstatus` CSR */
     csrw    mcause, s1
     csrw    mstatus, s2
     restore_mepc

+ 113 - 0
components/riscv/vectors_clic.S

@@ -0,0 +1,113 @@
+/*
+ * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "sdkconfig.h"
+#include "soc/soc.h"
+
+/* If memory protection interrupts are meant to trigger a panic, attach them to panic handler,
+ * else, attach them to the interrupt handler. */
+#if CONFIG_ESP_SYSTEM_MEMPROT_FEATURE
+    #define MEMPROT_ISR _panic_handler
+#else
+    #define MEMPROT_ISR _interrupt_handler
+#endif // CONFIG_ESP_SYSTEM_MEMPROT_FEATURE
+
+/* The system interrupts are not used for now, so trigger a panic every time one occurs. */
+#define _system_int_handler _panic_handler
+
+    /* Handlers defined in the `vector.S` file, common to all RISC-V targets */
+    .global _interrupt_handler
+    .global _panic_handler
+
+    .section .exception_vectors_table.text
+
+    /* Prevent the compiler from generating 2-byte instruction in the vector tables */
+    .option push
+    .option norvc
+
+    /**
+     * Non-hardware vectored interrupt entry. MTVEC CSR points here.
+     *
+     * On targets that use CLIC as their interrupt controller, when an exception occurs, the CPU
+     * jumps to the address stored in MTVEC[31:6] << 6. The CPU will also jump to this location
+     * if an interrupt is configured as non-vectored (CLIC_INT_ATTR.shv = 0).
+     *
+     * Because of the left-shift `<< 6`, this entry must be aligned on 64.
+     */
+    .global _vector_table
+    .type _vector_table, @function
+    .balign 0x40
+_vector_table:
+    j _panic_handler
+    .size _vector_table, .-_vector_table
+
+
+    /**
+     * Vectored interrupt table. MTVT CSR points here.
+     *
+     * If an interrupt occurs and is configured as (hardware) vectored, the CPU will jump to
+     * MTVT[31:0] + 4 * interrupt_id
+     *
+     * In the case of the ESP32P4, the interrupt matrix, between the CPU interrupt lines
+     * and the peripherals, offers 32 lines. As such, the interrupt_id between 0 and 31.
+     *
+     * Since the interrupts are initialized as vectored on CPU start, we can manage the special
+     * interrupts ETS_T1_WDT_INUM, ETS_CACHEERR_INUM and ETS_MEMPROT_ERR_INUM here.
+     */
+    .balign 0x40
+    .global _mtvt_table
+    .type _mtvt_table, @function
+_mtvt_table:
+    .word _system_int_handler       /* 0: System interrupt number. Exceptions are non-vectored, won't load this. */
+    .word _system_int_handler       /* 1: System interrupt number */
+    .word _system_int_handler       /* 2: System interrupt number */
+    .word _system_int_handler       /* 3: System interrupt number */
+    .word _system_int_handler       /* 4: System interrupt number */
+    .word _system_int_handler       /* 5: System interrupt number */
+    .word _system_int_handler       /* 6: System interrupt number */
+    .word _system_int_handler       /* 7: System interrupt number */
+    .word _system_int_handler       /* 8: System interrupt number */
+    .word _system_int_handler       /* 9: System interrupt number */
+    .word _system_int_handler       /* 10: System interrupt number */
+    .word _system_int_handler       /* 11: System interrupt number */
+    .word _system_int_handler       /* 12: System interrupt number */
+    .word _system_int_handler       /* 13: System interrupt number */
+    .word _system_int_handler       /* 14: System interrupt number */
+    .word _system_int_handler       /* 15: System interrupt number */
+    .word _interrupt_handler        /* 16: Free interrupt number */
+    .word _interrupt_handler        /* 17: Free interrupt number */
+    .word _interrupt_handler        /* 18: Free interrupt number */
+    .word _interrupt_handler        /* 19: Free interrupt number */
+    .word _interrupt_handler        /* 20: Free interrupt number */
+    .word _interrupt_handler        /* 21: Free interrupt number */
+    .word _interrupt_handler        /* 22: Free interrupt number */
+    .word _interrupt_handler        /* 23: Free interrupt number */
+    .word _interrupt_handler        /* 24: Free interrupt number */
+    .word _interrupt_handler        /* 25: Free interrupt number */
+    .word _interrupt_handler        /* 26: Free interrupt number */
+    .word _interrupt_handler        /* 27: Free interrupt number */
+    .word _interrupt_handler        /* 28: Free interrupt number */
+    .word _interrupt_handler        /* 29: Free interrupt number */
+    .word _interrupt_handler        /* 30: Free interrupt number */
+    .word _interrupt_handler        /* 31: Free interrupt number */
+    .word _interrupt_handler        /* 32: Free interrupt number */
+    .word _interrupt_handler        /* 33: Free interrupt number */
+    .word _interrupt_handler        /* 34: Free interrupt number */
+    .word _interrupt_handler        /* 35: Free interrupt number */
+    .word _interrupt_handler        /* 36: Free interrupt number */
+    .word _interrupt_handler        /* 37: Free interrupt number */
+    .word _interrupt_handler        /* 38: Free interrupt number */
+    .word _interrupt_handler        /* 39: Free interrupt number */
+    .word _panic_handler            /* 40: ETS_INT_WDT_INUM (+16) panic-interrupt (soc-level panic) */
+    .word _panic_handler            /* 41: ETS_CACHEERR_INUM (+16) panic-interrupt (soc-level panic) */
+    .word MEMPROT_ISR               /* 42: ETS_MEMPROT_ERR_INUM (+16) handler (soc-level panic) */
+    .word _interrupt_handler        /* 43: Free interrupt number */
+    .word _interrupt_handler        /* 44: Free interrupt number */
+    .word _interrupt_handler        /* 45: Free interrupt number */
+    .word _interrupt_handler        /* 46: Free interrupt number */
+    .word _interrupt_handler        /* 47: Free interrupt number */
+
+    .size _mtvt_table, .-_mtvt_table
+    .option pop

+ 90 - 0
components/riscv/vectors_intc.S

@@ -0,0 +1,90 @@
+/*
+ * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include "sdkconfig.h"
+#include "soc/soc.h"
+
+#if ETS_INT_WDT_INUM != 24
+    #error "ETS_INT_WDT_INUM expected to be 24"
+#endif
+
+/* If memory protection interrupts are meant to trigger a panic, attach them to panic handler,
+ * else, attach them to the interrupt handler. */
+#if CONFIG_ESP_SYSTEM_MEMPROT_FEATURE
+    #define MEMPROT_ISR _panic_handler
+#else
+    #define MEMPROT_ISR _interrupt_handler
+#endif // CONFIG_ESP_SYSTEM_MEMPROT_FEATURE
+
+/* Same goes for the assist debug interrupt */
+#if CONFIG_ESP_SYSTEM_HW_STACK_GUARD
+    #define ASTDBG_ISR _panic_handler
+#else
+    #define ASTDBG_ISR _interrupt_handler
+#endif // CONFIG_ESP_SYSTEM_HW_STACK_GUARD
+
+
+    /* Handlers defined in the `vector.S` file, common to all RISC-V targets */
+    .global _interrupt_handler
+    .global _panic_handler
+
+    .section .exception_vectors_table.text
+
+    /* This is the vector table. MTVEC points here.
+     *
+     * Use 4-byte instructions here. 1 instruction = 1 entry of the table.
+     * The CPU jumps to MTVEC (i.e. the first entry) in case of an exception,
+     * and (MTVEC & 0xfffffffc) + (mcause & 0x7fffffff) * 4, in case of an interrupt.
+     *
+     * Note: for our CPU, we need to place this on a 256-byte boundary, as CPU
+     * only uses the 24 MSBs of the MTVEC, i.e. (MTVEC & 0xffffff00).
+     */
+    .balign 0x100
+
+    /* Since each entry must take 4-byte, let's temporarily disable the compressed
+     * instruction set that could potentially generate 2-byte instructions. */
+    .option push
+    .option norvc
+
+    .global _vector_table
+    .type _vector_table, @function
+_vector_table:
+    j _panic_handler            /* 0: Exception entry */
+    j _interrupt_handler        /* 1: Free interrupt number */
+    j _interrupt_handler        /* 2: Free interrupt number */
+    j _interrupt_handler        /* 3: Free interrupt number */
+    j _interrupt_handler        /* 4: Free interrupt number */
+    j _interrupt_handler        /* 5: Free interrupt number */
+    j _interrupt_handler        /* 6: Free interrupt number */
+    j _interrupt_handler        /* 7: Free interrupt number */
+    j _interrupt_handler        /* 8: Free interrupt number */
+    j _interrupt_handler        /* 9: Free interrupt number */
+    j _interrupt_handler        /* 10: Free interrupt number */
+    j _interrupt_handler        /* 11: Free interrupt number */
+    j _interrupt_handler        /* 12: Free interrupt number */
+    j _interrupt_handler        /* 13: Free interrupt number */
+    j _interrupt_handler        /* 14: Free interrupt number */
+    j _interrupt_handler        /* 15: Free interrupt number */
+    j _interrupt_handler        /* 16: Free interrupt number */
+    j _interrupt_handler        /* 17: Free interrupt number */
+    j _interrupt_handler        /* 18: Free interrupt number */
+    j _interrupt_handler        /* 19: Free interrupt number */
+    j _interrupt_handler        /* 20: Free interrupt number */
+    j _interrupt_handler        /* 21: Free interrupt number */
+    j _interrupt_handler        /* 22: Free interrupt number */
+    j _interrupt_handler        /* 23: Free interrupt number */
+    j _panic_handler            /* 24: ETS_INT_WDT_INUM panic-interrupt (soc-level panic) */
+    j _panic_handler            /* 25: ETS_CACHEERR_INUM panic-interrupt (soc-level panic) */
+    j MEMPROT_ISR               /* 26: ETS_MEMPROT_ERR_INUM handler (soc-level panic) */
+    j ASTDBG_ISR                /* 27: ETS_ASSIST_DEBUG_INUM handler (soc-level panic) */
+    j _interrupt_handler        /* 28: Free interrupt number */
+    j _interrupt_handler        /* 29: Free interrupt number */
+    j _interrupt_handler        /* 30: Free interrupt number */
+    j _interrupt_handler        /* 31: Free interrupt number */
+
+    .size _vector_table, .-_vector_table
+
+    /* Re-enable the compressed instruction set it is was enabled before */
+    .option pop

+ 4 - 0
components/soc/esp32p4/include/soc/Kconfig.soc_caps.in

@@ -207,6 +207,10 @@ config SOC_INT_CLIC_SUPPORTED
     bool
     default y
 
+config SOC_INT_HW_NESTED_SUPPORTED
+    bool
+    default y
+
 config SOC_BRANCH_PREDICTOR_SUPPORTED
     bool
     default y

+ 23 - 3
components/soc/esp32p4/include/soc/interrupt_reg.h

@@ -3,10 +3,30 @@
  *
  * SPDX-License-Identifier: Apache-2.0
  */
+#pragma once
 
 #include "soc/clic_reg.h"
 #include "soc/soc_caps.h"
 
-// ESP32P4 uses the CLIC controller as the interrupt controller (SOC_INT_CLIC_SUPPORTED = y)
-#define INTERRUPT_CORE0_CPU_INT_THRESH_REG CLIC_INT_THRESH_REG
-#define INTERRUPT_CORE1_CPU_INT_THRESH_REG CLIC_INT_THRESH_REG
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * ESP32P4 uses the CLIC controller as the interrupt controller (SOC_INT_CLIC_SUPPORTED = y)
+ *
+ * The memory map for interrupt registers is on a per-core basis, CLIC_INT_THRESH_REG points to
+ * the current core interrupt register, whereas CLIC_INT_THRESH_REG + DUALCORE_CLIC_CTRL_OFF points
+ * to the other core registers, regardless of the core we are currently running on.
+ */
+#define INTERRUPT_CURRENT_CORE_INT_THRESH_REG   (CLIC_INT_THRESH_REG)
+#define INTERRUPT_OTHER_CORE_INT_THRESH_REG     (CLIC_INT_THRESH_REG + DUALCORE_CLIC_CTRL_OFF)
+
+
+#define INTERRUPT_CORE0_CPU_INT_THRESH_REG (rv_utils_get_core_id() == 0 ? INTERRUPT_CURRENT_CORE_INT_THRESH_REG : INTERRUPT_OTHER_CORE_INT_THRESH_REG)
+#define INTERRUPT_CORE1_CPU_INT_THRESH_REG (rv_utils_get_core_id() == 1 ? INTERRUPT_CURRENT_CORE_INT_THRESH_REG : INTERRUPT_OTHER_CORE_INT_THRESH_REG)
+
+
+#ifdef __cplusplus
+}
+#endif

+ 1 - 1
components/soc/esp32p4/include/soc/soc.h

@@ -230,7 +230,7 @@
 //On RISC-V CPUs, the interrupt sources are all external interrupts, whose type, source and priority are configured by SW.
 //There is no HW NMI conception. SW should controlled the masked levels through INT_THRESH_REG.
 
-//CPU0 Interrupt number reserved in riscv/vector.S, not touch this.
+//CPU0 Interrupt number reserved in riscv/vector_clic.S, do not touch this.
 #define ETS_T1_WDT_INUM                         24
 #define ETS_CACHEERR_INUM                       25
 #define ETS_MEMPROT_ERR_INUM                    26

+ 1 - 0
components/soc/esp32p4/include/soc/soc_caps.h

@@ -137,6 +137,7 @@
 #define SOC_CPU_HAS_FLEXIBLE_INTC       1
 #define SOC_INT_PLIC_SUPPORTED          0       //riscv platform-level interrupt controller
 #define SOC_INT_CLIC_SUPPORTED          1
+#define SOC_INT_HW_NESTED_SUPPORTED     1       // Support for hardware interrupts nesting
 #define SOC_BRANCH_PREDICTOR_SUPPORTED  1
 
 #define SOC_CPU_BREAKPOINTS_NUM         4

+ 128 - 128
components/soc/esp32p4/interrupts.c

@@ -7,132 +7,132 @@
 #include "soc/interrupts.h"
 
 const char *const esp_isr_names[] = {
-    [0] = "LP_RTC",
-    [1] = "LP_WDT",
-    [2] = "LP_TIMER0",
-    [3] = "LP_TIMER1",
-    [4] = "MB_HP",
-    [5] = "MB_LP",
-    [6] = "PMU0",
-    [7] = "PMU1",
-    [8] = "LP_ANA",
-    [9] = "LP_ADC",
-    [10] = "LP_GPIO",
-    [11] = "LP_I2C",
-    [12] = "LP_I2S",
-    [13] = "LP_SPI",
-    [14] = "LP_TOUCH",
-    [15] = "LP_TSENS",
-    [16] = "LP_UART",
-    [17] = "LP_EFUSE",
-    [18] = "LP_SW",
-    [19] = "LP_SYSREG",
-    [20] = "LP_HUK",
-    [21] = "SYS_ICM",
-    [22] = "USB_DEVICE",
-    [23] = "SDIO_HOST",
-    [24] = "GDMA",
-    [25] = "GPSPI2",
-    [26] = "GPSPI3",
-    [27] = "I2S0",
-    [28] = "I2S1",
-    [29] = "I2S2",
-    [30] = "UHCI0",
-    [31] = "UART0",
-    [32] = "UART1",
-    [33] = "UART2",
-    [34] = "UART3",
-    [35] = "UART4",
-    [36] = "LCD_CAM",
-    [37] = "ADC",
-    [38] = "PWM0",
-    [39] = "PWM1",
-    [40] = "CAN0",
-    [41] = "CAN1",
-    [42] = "CAN2",
-    [43] = "RMT",
-    [44] = "I2C0",
-    [45] = "I2C1",
-    [46] = "TG0_T0",
-    [47] = "TG0_T1",
-    [48] = "TG0_WDT",
-    [49] = "TG1_T0",
-    [50] = "TG1_T1",
-    [51] = "TG1_WDT",
-    [52] = "LEDC",
-    [53] = "SYSTIMER_TARGET0",
-    [54] = "SYSTIMER_TARGET1",
-    [55] = "SYSTIMER_TARGET2",
-    [56] = "AHB_PDMA_IN_CH0",
-    [57] = "AHB_PDMA_IN_CH1",
-    [58] = "AHB_PDMA_IN_CH2",
-    [59] = "AHB_PDMA_OUT_CH0",
-    [60] = "AHB_PDMA_OUT_CH1",
-    [61] = "AHB_PDMA_OUT_CH2",
-    [62] = "AXI_PDMA_IN_CH0",
-    [63] = "AXI_PDMA_IN_CH1",
-    [64] = "AXI_PDMA_IN_CH2",
-    [65] = "AXI_PDMA_OUT_CH0",
-    [66] = "AXI_PDMA_OUT_CH1",
-    [67] = "AXI_PDMA_OUT_CH2",
-    [68] = "RSA",
-    [69] = "AES",
-    [70] = "SHA",
-    [71] = "ECC",
-    [72] = "ECDSA",
-    [73] = "KM",
-    [74] = "GPIO_INT0",
-    [75] = "GPIO_INT1",
-    [76] = "GPIO_INT2",
-    [77] = "GPIO_INT3",
-    [78] = "GPIO_PAD_COMP",
-    [79] = "CPU_INT_FROM_CPU_0",
-    [80] = "CPU_INT_FROM_CPU_1",
-    [81] = "CPU_INT_FROM_CPU_2",
-    [82] = "CPU_INT_FROM_CPU_3",
-    [83] = "CACHE",
-    [84] = "FLASH_MSPI",
-    [85] = "CSI_BRIDGE",
-    [86] = "DSI_BRIDGE",
-    [87] = "CSI",
-    [88] = "DSI",
-    [89] = "GMII_PHY",
-    [90] = "LPI",
-    [91] = "PMT",
-    [92] = "SBD",
-    [93] = "USB_OTG",
-    [94] = "USB_OTG_ENDP_MULTI_PROC",
-    [95] = "JPEG",
-    [96] = "PPA",
-    [97] = "CORE0_TRACE",
-    [98] = "CORE1_TRACE",
-    [99] = "HP_CORE",
-    [100] = "ISP",
-    [101] = "I3C",
-    [102] = "I3C_SLV",
-    [103] = "USB_OTG11",
-    [104] = "DMA2D_IN_CH0",
-    [105] = "DMA2D_IN_CH1",
-    [106] = "DMA2D_OUT_CH0",
-    [107] = "DMA2D_OUT_CH1",
-    [108] = "DMA2D_OUT_CH2",
-    [109] = "PSRAM_MSPI",
-    [110] = "HP_SYSREG",
-    [111] = "PCNT",
-    [112] = "HP_PAU",
-    [113] = "HP_PARLIO_RX",
-    [114] = "HP_PARLIO_TX",
-    [115] = "H264_DMA2D_OUT_CH0",
-    [116] = "H264_DMA2D_OUT_CH1",
-    [117] = "H264_DMA2D_OUT_CH2",
-    [118] = "H264_DMA2D_OUT_CH3",
-    [119] = "H264_DMA2D_OUT_CH4",
-    [120] = "H264_DMA2D_IN_CH0",
-    [121] = "H264_DMA2D_IN_CH1",
-    [122] = "H264_DMA2D_IN_CH2",
-    [123] = "H264_DMA2D_IN_CH3",
-    [124] = "H264_DMA2D_IN_CH4",
-    [125] = "H264_DMA2D_IN_CH5",
-    [126] = "H264_REG",
-    [127] = "ASSIST_DEBUG",
+    [ETS_LP_RTC_INTR_SOURCE]             = "LP_RTC",
+    [ETS_LP_WDT_INTR_SOURCE]             = "LP_WDT",
+    [ETS_LP_TIMER_REG0_INTR_SOURCE]      = "LP_TIMER_REG0",
+    [ETS_LP_TIMER_REG1_INTR_SOURCE]      = "LP_TIMER_REG1",
+    [ETS_MB_HP_INTR_SOURCE]              = "MB_HP",
+    [ETS_MB_LP_INTR_SOURCE]              = "MB_LP",
+    [ETS_PMU_0_INTR_SOURCE]              = "PMU_0",
+    [ETS_PMU_1_INTR_SOURCE]              = "PMU_1",
+    [ETS_LP_ANAPERI_INTR_SOURCE]         = "LP_ANAPERI",
+    [ETS_LP_ADC_INTR_SOURCE]             = "LP_ADC",
+    [ETS_LP_GPIO_INTR_SOURCE]            = "LP_GPIO",
+    [ETS_LP_I2C_INTR_SOURCE]             = "LP_I2C",
+    [ETS_LP_I2S_INTR_SOURCE]             = "LP_I2S",
+    [ETS_LP_SPI_INTR_SOURCE]             = "LP_SPI",
+    [ETS_LP_TOUCH_INTR_SOURCE]           = "LP_TOUCH",
+    [ETS_LP_TSENS_INTR_SOURCE]           = "LP_TSENS",
+    [ETS_LP_UART_INTR_SOURCE]            = "LP_UART",
+    [ETS_LP_EFUSE_INTR_SOURCE]           = "LP_EFUSE",
+    [ETS_LP_SW_INTR_SOURCE]              = "LP_SW",
+    [ETS_LP_SYSREG_INTR_SOURCE]          = "LP_SYSREG",
+    [ETS_LP_HUK_INTR_SOURCE]             = "LP_HUK",
+    [ETS_SYS_ICM_INTR_SOURCE]            = "SYS_ICM",
+    [ETS_USB_DEVICE_INTR_SOURCE]         = "USB_DEVICE",
+    [ETS_SDIO_HOST_INTR_SOURCE]          = "SDIO_HOST",
+    [ETS_GDMA_INTR_SOURCE]               = "GDMA",
+    [ETS_SPI2_INTR_SOURCE]               = "SPI2",
+    [ETS_SPI3_INTR_SOURCE]               = "SPI3",
+    [ETS_I2S0_INTR_SOURCE]               = "I2S0",
+    [ETS_I2S1_INTR_SOURCE]               = "I2S1",
+    [ETS_I2S2_INTR_SOURCE]               = "I2S2",
+    [ETS_UHCI0_INTR_SOURCE]              = "UHCI0",
+    [ETS_UART0_INTR_SOURCE]              = "UART0",
+    [ETS_UART1_INTR_SOURCE]              = "UART1",
+    [ETS_UART2_INTR_SOURCE]              = "UART2",
+    [ETS_UART3_INTR_SOURCE]              = "UART3",
+    [ETS_UART4_INTR_SOURCE]              = "UART4",
+    [ETS_LCD_CAM_INTR_SOURCE]            = "LCD_CAM",
+    [ETS_ADC_INTR_SOURCE]                = "ADC",
+    [ETS_PWM0_INTR_SOURCE]               = "PWM0",
+    [ETS_PWM1_INTR_SOURCE]               = "PWM1",
+    [ETS_CAN0_INTR_SOURCE]               = "CAN0",
+    [ETS_CAN1_INTR_SOURCE]               = "CAN1",
+    [ETS_CAN2_INTR_SOURCE]               = "CAN2",
+    [ETS_RMT_INTR_SOURCE]                = "RMT",
+    [ETS_I2C0_INTR_SOURCE]               = "I2C0",
+    [ETS_I2C1_INTR_SOURCE]               = "I2C1",
+    [ETS_TG0_T0_INTR_SOURCE]             = "TG0_T0",
+    [ETS_TG0_T1_INTR_SOURCE]             = "TG0_T1",
+    [ETS_TG0_WDT_LEVEL_INTR_SOURCE]      = "TG0_WDT_LEVEL",
+    [ETS_TG1_T0_INTR_SOURCE]             = "TG1_T0",
+    [ETS_TG1_T1_INTR_SOURCE]             = "TG1_T1",
+    [ETS_TG1_WDT_LEVEL_INTR_SOURCE]      = "TG1_WDT_LEVEL",
+    [ETS_LEDC_INTR_SOURCE]               = "LEDC",
+    [ETS_SYSTIMER_TARGET0_INTR_SOURCE]   = "SYSTIMER_TARGET0",
+    [ETS_SYSTIMER_TARGET1_INTR_SOURCE]   = "SYSTIMER_TARGET1",
+    [ETS_SYSTIMER_TARGET2_INTR_SOURCE]   = "SYSTIMER_TARGET2",
+    [ETS_AHB_PDMA_IN_CH0_INTR_SOURCE]    = "AHB_PDMA_IN_CH0",
+    [ETS_AHB_PDMA_IN_CH1_INTR_SOURCE]    = "AHB_PDMA_IN_CH1",
+    [ETS_AHB_PDMA_IN_CH2_INTR_SOURCE]    = "AHB_PDMA_IN_CH2",
+    [ETS_AHB_PDMA_OUT_CH0_INTR_SOURCE]   = "AHB_PDMA_OUT_CH0",
+    [ETS_AHB_PDMA_OUT_CH1_INTR_SOURCE]   = "AHB_PDMA_OUT_CH1",
+    [ETS_AHB_PDMA_OUT_CH2_INTR_SOURCE]   = "AHB_PDMA_OUT_CH2",
+    [ETS_AXI_PDMA_IN_CH0_INTR_SOURCE]    = "AXI_PDMA_IN_CH0",
+    [ETS_AXI_PDMA_IN_CH1_INTR_SOURCE]    = "AXI_PDMA_IN_CH1",
+    [ETS_AXI_PDMA_IN_CH2_INTR_SOURCE]    = "AXI_PDMA_IN_CH2",
+    [ETS_AXI_PDMA_OUT_CH0_INTR_SOURCE]   = "AXI_PDMA_OUT_CH0",
+    [ETS_AXI_PDMA_OUT_CH1_INTR_SOURCE]   = "AXI_PDMA_OUT_CH1",
+    [ETS_AXI_PDMA_OUT_CH2_INTR_SOURCE]   = "AXI_PDMA_OUT_CH2",
+    [ETS_RSA_INTR_SOURCE]                = "RSA",
+    [ETS_AES_INTR_SOURCE]                = "AES",
+    [ETS_SHA_INTR_SOURCE]                = "SHA",
+    [ETS_ECC_INTR_SOURCE]                = "ECC",
+    [ETS_ECDSA_INTR_SOURCE]              = "ECDSA",
+    [ETS_KM_INTR_SOURCE]                 = "KM",
+    [ETS_GPIO_INTR0_SOURCE]              = "GPIO_INT0",
+    [ETS_GPIO_INTR1_SOURCE]              = "GPIO_INT1",
+    [ETS_GPIO_INTR2_SOURCE]              = "GPIO_INT2",
+    [ETS_GPIO_INTR3_SOURCE]              = "GPIO_INT3",
+    [ETS_GPIO_PAD_COMP_INTR_SOURCE]      = "GPIO_PAD_COMP",
+    [ETS_FROM_CPU_INTR0_SOURCE]          = "CPU_INT_FROM_CPU_0",
+    [ETS_FROM_CPU_INTR1_SOURCE]          = "CPU_INT_FROM_CPU_1",
+    [ETS_FROM_CPU_INTR2_SOURCE]          = "CPU_INT_FROM_CPU_2",
+    [ETS_FROM_CPU_INTR3_SOURCE]          = "CPU_INT_FROM_CPU_3",
+    [ETS_CACHE_INTR_SOURCE]              = "CACHE",
+    [ETS_MSPI_INTR_SOURCE]               = "MSPI",
+    [ETS_CSI_BRIDGE_INTR_SOURCE]         = "CSI_BRIDGE",
+    [ETS_DSI_BRIDGE_INTR_SOURCE]         = "DSI_BRIDGE",
+    [ETS_CSI_INTR_SOURCE]                = "CSI",
+    [ETS_DSI_INTR_SOURCE]                = "DSI",
+    [ETS_GMII_PHY_INTR_SOURCE]           = "GMII_PHY",
+    [ETS_LPI_INTR_SOURCE]                = "LPI",
+    [ETS_PMT_INTR_SOURCE]                = "PMT",
+    [ETS_SBD_INTR_SOURCE]                = "SBD",
+    [ETS_USB_OTG_INTR_SOURCE]            = "USB_OTG",
+    [ETS_USB_OTG_ENDP_MULTI_PROC_INTR_SOURCE] = "USB_OTG_ENDP_MULTI_PROC",
+    [ETS_JPEG_INTR_SOURCE]               = "JPEG",
+    [ETS_PPA_INTR_SOURCE]                = "PPA",
+    [ETS_CORE0_TRACE_INTR_SOURCE]        = "CORE0_TRACE",
+    [ETS_CORE1_TRACE_INTR_SOURCE]        = "CORE1_TRACE",
+    [ETS_HP_CORE_CTRL_INTR_SOURCE]       = "HP_CORE_CTRL",
+    [ETS_ISP_INTR_SOURCE]                = "ISP",
+    [ETS_I3C_MST_INTR_SOURCE]            = "I3C_MST",
+    [ETS_I3C_SLV_INTR_SOURCE]            = "I3C_SLV",
+    [ETS_USB_OTG11_CH0_INTR_SOURCE]      = "USB_OTG11_CH0",
+    [ETS_DMA2D_IN_CH0_INTR_SOURCE]       = "DMA2D_IN_CH0",
+    [ETS_DMA2D_IN_CH1_INTR_SOURCE]       = "DMA2D_IN_CH1",
+    [ETS_DMA2D_OUT_CH0_INTR_SOURCE]      = "DMA2D_OUT_CH0",
+    [ETS_DMA2D_OUT_CH1_INTR_SOURCE]      = "DMA2D_OUT_CH1",
+    [ETS_DMA2D_OUT_CH2_INTR_SOURCE]      = "DMA2D_OUT_CH2",
+    [ETS_PSRAM_MSPI_INTR_SOURCE]         = "PSRAM_MSPI",
+    [ETS_HP_SYSREG_INTR_SOURCE]          = "HP_SYSREG",
+    [ETS_PCNT_INTR_SOURCE]               = "PCNT",
+    [ETS_HP_PAU_INTR_SOURCE]             = "HP_PAU",
+    [ETS_HP_PARLIO_RX_INTR_SOURCE]       = "HP_PARLIO_RX",
+    [ETS_HP_PARLIO_TX_INTR_SOURCE]       = "HP_PARLIO_TX",
+    [ETS_H264_DMA2D_OUT_CH0_INTR_SOURCE] = "H264_DMA2D_OUT_CH0",
+    [ETS_H264_DMA2D_OUT_CH1_INTR_SOURCE] = "H264_DMA2D_OUT_CH1",
+    [ETS_H264_DMA2D_OUT_CH2_INTR_SOURCE] = "H264_DMA2D_OUT_CH2",
+    [ETS_H264_DMA2D_OUT_CH3_INTR_SOURCE] = "H264_DMA2D_OUT_CH3",
+    [ETS_H264_DMA2D_OUT_CH4_INTR_SOURCE] = "H264_DMA2D_OUT_CH4",
+    [ETS_H264_DMA2D_IN_CH0_INTR_SOURCE]  = "H264_DMA2D_IN_CH0",
+    [ETS_H264_DMA2D_IN_CH1_INTR_SOURCE]  = "H264_DMA2D_IN_CH1",
+    [ETS_H264_DMA2D_IN_CH2_INTR_SOURCE]  = "H264_DMA2D_IN_CH2",
+    [ETS_H264_DMA2D_IN_CH3_INTR_SOURCE]  = "H264_DMA2D_IN_CH3",
+    [ETS_H264_DMA2D_IN_CH4_INTR_SOURCE]  = "H264_DMA2D_IN_CH4",
+    [ETS_H264_DMA2D_IN_CH5_INTR_SOURCE]  = "H264_DMA2D_IN_CH5",
+    [ETS_H264_REG_INTR_SOURCE]           = "H264_REG",
+    [ETS_ASSIST_DEBUG_INTR_SOURCE]       = "ASSIST_DEBUG",
 };