fix(build): add workaround for cm.push that triggers interrupt

This commit is contained in:
Alexey Lapshin
2025-06-05 16:31:36 +07:00
parent a5b54a7ea3
commit 6ed3fe13ca
7 changed files with 143 additions and 98 deletions

View File

@@ -12,6 +12,7 @@
#include "soc/soc_caps.h" #include "soc/soc_caps.h"
#include "esp_attr.h" #include "esp_attr.h"
#include "riscv/csr.h" #include "riscv/csr.h"
#include "riscv/csr_clic.h"
#if SOC_INT_CLIC_SUPPORTED #if SOC_INT_CLIC_SUPPORTED
@@ -21,102 +22,6 @@
extern "C" { extern "C" {
#endif #endif
/**
* @brief Set global masking level. When using the CLIC, all interrupt priority levels less than or equal to the threshold
* level are masked. Since the default priority for the interrupt is 1, set this macro to 0 to enable them all.
*/
#define RVHAL_INTR_ENABLE_THRESH 0
/**
* @brief Bitmask to enable the vector mode when writing MTVEC CSR.
* Setting mode field to 3 treats `MTVT + 4 * interrupt_id` as the service entry address for HW vectored interrupts.
*/
#define MTVEC_MODE_CSR 3
/**
* 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 16
/**
* @brief CSR to set the interrupt jump table address is MTVT.
*/
#define MTVT_CSR 0x307
#define UTVT_CSR 0x007
#if CONFIG_IDF_TARGET_ESP32P4 && CONFIG_ESP32P4_SELECTS_REV_LESS_V3
/**
* The ESP32-P4 and the beta version of the ESP32-C5 implement a non-standard version of the CLIC:
* - The interrupt threshold is configured via a memory-mapped register instead of a CSR
* - The mintstatus CSR is at 0x346 instead of 0xFB1 as per the official specification
*/
#define INTTHRESH_STANDARD 0
#define MINTSTATUS_CSR 0x346
#elif CONFIG_IDF_TARGET_ESP32C5 || CONFIG_IDF_TARGET_ESP32C61 || CONFIG_IDF_TARGET_ESP32H4 || !CONFIG_ESP32P4_SELECTS_REV_LESS_V3
/* The ESP32-C5 (MP), C61, H4 and P4 (since REV2) use the standard CLIC specification, for example, it defines the mintthresh CSR */
#define INTTHRESH_STANDARD 1
#define MINTSTATUS_CSR 0xFB1
#define UINTSTATUS_CSR 0xCB1
#define MINTTHRESH_CSR 0x347
#define UINTTHRESH_CSR 0x047
#else
#error "Check the implementation of the CLIC on this target."
#endif
/**
* @brief Convert a priority level from 8-bit to NLBITS and NLBITS to 8-bit
*
* On CLIC, the interrupt threshold is stored in the upper (NLBITS) of the mintthresh register, with the other (8 - NLBITS)
* defaulted to 1. We form the interrupt level bits here to avoid doing this at run time
*/
#define NLBITS_SHIFT (8 - NLBITS)
#define NLBITS_MASK ((1 << NLBITS) - 1)
#define BYTE_TO_NLBITS(level) (((level) >> NLBITS_SHIFT) & NLBITS_MASK)
/* Align the level to the left, and put 1 in the lowest bits */
#define NLBITS_TO_BYTE(level) (((level) << NLBITS_SHIFT) | ((1 << NLBITS_SHIFT) - 1))
/**
* @brief In the minstatus CSR, the `mil` field is present from bit 24 to bit 31 (included)
*/
#define MINTSTATUS_MIL_S 24
#define MINTSTATUS_MIL_V 0xFF
#if INTTHRESH_STANDARD
/* Helper macro to translate absolute interrupt level to CLIC interrupt threshold bits in the mintthresh reg */
#define CLIC_INT_THRESH(intlevel) (NLBITS_TO_BYTE(intlevel))
/* Helper macro to translate a CLIC interrupt threshold bits to an absolute interrupt level */
#define CLIC_THRESH_TO_INT(intlevel) (BYTE_TO_NLBITS((intlevel)))
/* Helper macro to translate a CLIC status threshold bits to an absolute interrupt level */
#define CLIC_STATUS_TO_INT(status) (BYTE_TO_NLBITS((status >> MINTSTATUS_MIL_S) & MINTSTATUS_MIL_V))
#else
/* For the non-standard intthresh implementation the threshold is stored in the upper 8 bits of CLIC_CPU_INT_THRESH reg */
/* Helper macro to translate absolute interrupt level to CLIC interrupt threshold bits in the mintthresh reg */
#define CLIC_INT_THRESH(intlevel) (NLBITS_TO_BYTE(intlevel) << CLIC_CPU_INT_THRESH_S)
/* Helper macro to translate a CLIC interrupt threshold bits to an absolute interrupt level */
#define CLIC_THRESH_TO_INT(intlevel) (BYTE_TO_NLBITS((intlevel >> CLIC_CPU_INT_THRESH_S) & CLIC_CPU_INT_THRESH_V))
/* Helper macro to translate a CLIC status threshold bits to an absolute interrupt level */
#define CLIC_STATUS_TO_INT(status) (BYTE_TO_NLBITS((status >> MINTSTATUS_MIL_S) & MINTSTATUS_MIL_V))
#endif //INTTHRESH_STANDARD
/* Helper macro to set interrupt level RVHAL_EXCM_LEVEL. Used during critical sections */
#define RVHAL_EXCM_LEVEL_CLIC (CLIC_INT_THRESH(RVHAL_EXCM_LEVEL - 1))
/* Helper macro to enable interrupts. */
#define RVHAL_INTR_ENABLE_THRESH_CLIC (CLIC_INT_THRESH(RVHAL_INTR_ENABLE_THRESH))
#if CONFIG_SECURE_ENABLE_TEE #if CONFIG_SECURE_ENABLE_TEE
#define IS_PRV_M_MODE() (RV_READ_CSR(CSR_PRV_MODE) == PRV_M) #define IS_PRV_M_MODE() (RV_READ_CSR(CSR_PRV_MODE) == PRV_M)
#else #else

View File

@@ -0,0 +1,95 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "soc/interrupt_reg.h"
#include "soc/soc_caps.h"
#if SOC_INT_CLIC_SUPPORTED
/**
* @brief Set global masking level. When using the CLIC, all interrupt priority levels less than or equal to the threshold
* level are masked. Since the default priority for the interrupt is 1, set this macro to 0 to enable them all.
*/
#define RVHAL_INTR_ENABLE_THRESH 0
/**
* @brief Bitmask to enable the vector mode when writing MTVEC CSR.
* Setting mode field to 3 treats `MTVT + 4 * interrupt_id` as the service entry address for HW vectored interrupts.
*/
#define MTVEC_MODE_CSR 3
/**
* 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 16
/**
* @brief CSR to set the interrupt jump table address is MTVT.
*/
#define MTVT_CSR 0x307
#define UTVT_CSR 0x007
#if INTTHRESH_STANDARD
/* The ESP32-C5 (MP), C61, H4 and P4 (since REV2) use the standard CLIC specification, for example, it defines the mintthresh CSR */
#define MINTSTATUS_CSR 0xFB1
#define UINTSTATUS_CSR 0xCB1
#define MINTTHRESH_CSR 0x347
#define UINTTHRESH_CSR 0x047
#elif !defined(MINTSTATUS_CSR)
#error "Non-standard CLIC CSRs must be defined for the current target!"
#endif
/**
* @brief Convert a priority level from 8-bit to NLBITS and NLBITS to 8-bit
*
* On CLIC, the interrupt threshold is stored in the upper (NLBITS) of the mintthresh register, with the other (8 - NLBITS)
* defaulted to 1. We form the interrupt level bits here to avoid doing this at run time
*/
#define NLBITS_SHIFT (8 - NLBITS)
#define NLBITS_MASK ((1 << NLBITS) - 1)
#define BYTE_TO_NLBITS(level) (((level) >> NLBITS_SHIFT) & NLBITS_MASK)
/* Align the level to the left, and put 1 in the lowest bits */
#define NLBITS_TO_BYTE(level) (((level) << NLBITS_SHIFT) | ((1 << NLBITS_SHIFT) - 1))
/**
* @brief In the minstatus CSR, the `mil` field is present from bit 24 to bit 31 (included)
*/
#define MINTSTATUS_MIL_S 24
#define MINTSTATUS_MIL_V 0xFF
#if INTTHRESH_STANDARD
/* Helper macro to translate absolute interrupt level to CLIC interrupt threshold bits in the mintthresh reg */
#define CLIC_INT_THRESH(intlevel) (NLBITS_TO_BYTE(intlevel))
/* Helper macro to translate a CLIC interrupt threshold bits to an absolute interrupt level */
#define CLIC_THRESH_TO_INT(intlevel) (BYTE_TO_NLBITS((intlevel)))
/* Helper macro to translate a CLIC status threshold bits to an absolute interrupt level */
#define CLIC_STATUS_TO_INT(status) (BYTE_TO_NLBITS((status >> MINTSTATUS_MIL_S) & MINTSTATUS_MIL_V))
#else
/* For the non-standard intthresh implementation the threshold is stored in the upper 8 bits of CLIC_CPU_INT_THRESH reg */
/* Helper macro to translate absolute interrupt level to CLIC interrupt threshold bits in the mintthresh reg */
#define CLIC_INT_THRESH(intlevel) (NLBITS_TO_BYTE(intlevel) << CLIC_CPU_INT_THRESH_S)
/* Helper macro to translate a CLIC interrupt threshold bits to an absolute interrupt level */
#define CLIC_THRESH_TO_INT(intlevel) (BYTE_TO_NLBITS((intlevel >> CLIC_CPU_INT_THRESH_S) & CLIC_CPU_INT_THRESH_V))
/* Helper macro to translate a CLIC status threshold bits to an absolute interrupt level */
#define CLIC_STATUS_TO_INT(status) (BYTE_TO_NLBITS((status >> MINTSTATUS_MIL_S) & MINTSTATUS_MIL_V))
#endif //INTTHRESH_STANDARD
/* Helper macro to set interrupt level RVHAL_EXCM_LEVEL. Used during critical sections */
#define RVHAL_EXCM_LEVEL_CLIC (CLIC_INT_THRESH(RVHAL_EXCM_LEVEL - 1))
/* Helper macro to enable interrupts. */
#define RVHAL_INTR_ENABLE_THRESH_CLIC (CLIC_INT_THRESH(RVHAL_INTR_ENABLE_THRESH))
#endif /* SOC_INT_CLIC_SUPPORTED */

View File

@@ -5,7 +5,7 @@
*/ */
#include "soc/soc.h" #include "soc/soc.h"
#include "soc/interrupt_reg.h" #include "riscv/csr_clic.h"
#include "riscv/rvruntime-frames.h" #include "riscv/rvruntime-frames.h"
#include "soc/soc_caps.h" #include "soc/soc_caps.h"
#include "sdkconfig.h" #include "sdkconfig.h"
@@ -181,6 +181,20 @@
#endif #endif
.endm .endm
.macro mintthresh_csr_disable reg
#if __riscv_zcmp && INTTHRESH_STANDARD
/* Workaround for triggering an interrupt even when mstatus.mie is 0, when cm.push is called. */
li t0, 0xff
csrrw \reg, MINTTHRESH_CSR, t0
#endif
.endm
.macro mintthresh_csr_restore reg
#if __riscv_zcmp && INTTHRESH_STANDARD
csrw MINTTHRESH_CSR, \reg
#endif
.endm
.macro xret .macro xret
#if CONFIG_SECURE_ENABLE_TEE #if CONFIG_SECURE_ENABLE_TEE
uret uret
@@ -216,6 +230,8 @@ _panic_handler:
/* Allocate space on the stack and store general purpose registers */ /* Allocate space on the stack and store general purpose registers */
save_general_regs RV_STK_FRMSZ save_general_regs RV_STK_FRMSZ
mintthresh_csr_disable s5
/* As gp register is not saved by the macro, save it here */ /* As gp register is not saved by the macro, save it here */
sw gp, RV_STK_GP(sp) sw gp, RV_STK_GP(sp)
@@ -366,6 +382,8 @@ _store_mcause:
* Restore the registers and return from the exception. * Restore the registers and return from the exception.
*/ */
_return_from_exception: _return_from_exception:
mintthresh_csr_restore s5
restore_xepc restore_xepc
/* MTVEC and SP are assumed to be unmodified. /* MTVEC and SP are assumed to be unmodified.
* MSTATUS, MHARTID, MTVAL are read-only and not restored. * MSTATUS, MHARTID, MTVAL are read-only and not restored.
@@ -465,6 +483,8 @@ _tee_interrupt_handler:
/* After dispatch c handler, disable interrupt to make freertos make context switch */ /* After dispatch c handler, disable interrupt to make freertos make context switch */
mintthresh_csr_disable s5
disable_intr disable_intr
/* MIE cleared. Nested interrupts are disabled */ /* MIE cleared. Nested interrupts are disabled */
@@ -510,6 +530,9 @@ _skip_thresh_reset:
csrw mcause, s1 csrw mcause, s1
csrw mstatus, a0 csrw mstatus, a0
#endif #endif
mintthresh_csr_restore s5
restore_xepc restore_xepc
restore_general_regs restore_general_regs
/* exit, this will also re-enable the interrupts */ /* exit, this will also re-enable the interrupts */

View File

@@ -19,6 +19,8 @@ extern "C" {
/* We only have a single core on the C5, CORE0 */ /* We only have a single core on the C5, CORE0 */
#define INTERRUPT_CORE0_CPU_INT_THRESH_REG INTERRUPT_CURRENT_CORE_INT_THRESH_REG #define INTERRUPT_CORE0_CPU_INT_THRESH_REG INTERRUPT_CURRENT_CORE_INT_THRESH_REG
#define INTTHRESH_STANDARD 1
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -14,3 +14,5 @@
#define INTERRUPT_CURRENT_CORE_INT_THRESH_REG (CLIC_INT_THRESH_REG) #define INTERRUPT_CURRENT_CORE_INT_THRESH_REG (CLIC_INT_THRESH_REG)
#define INTERRUPT_CORE0_CPU_INT_THRESH_REG INTERRUPT_CURRENT_CORE_INT_THRESH_REG #define INTERRUPT_CORE0_CPU_INT_THRESH_REG INTERRUPT_CURRENT_CORE_INT_THRESH_REG
#define INTTHRESH_STANDARD 1

View File

@@ -12,3 +12,5 @@
#define INTERRUPT_CURRENT_CORE_INT_THRESH_REG (CLIC_INT_THRESH_REG) #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_OTHER_CORE_INT_THRESH_REG (CLIC_INT_THRESH_REG + DUALCORE_CLIC_CTRL_OFF)
#define INTTHRESH_STANDARD 1

View File

@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -25,6 +25,22 @@ extern "C" {
#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_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) #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)
#if CONFIG_ESP32P4_SELECTS_REV_LESS_V3
/**
* The ESP32-P4 implements a non-standard version of the CLIC:
* - The interrupt threshold is configured via a memory-mapped register instead of a CSR
* - The mintstatus CSR is at 0x346 instead of 0xFB1 as per the official specification
*/
#define INTTHRESH_STANDARD 0
#define MINTSTATUS_CSR 0x346
#else /* CONFIG_ESP32P4_SELECTS_REV_LESS_V3 */
#define INTTHRESH_STANDARD 1
#endif /* CONFIG_ESP32P4_SELECTS_REV_LESS_V3 */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif