fix(riscv): implement a workaround for Zcmp hardware bug

This commit is contained in:
Omar Chebib
2026-05-12 17:58:23 +08:00
committed by BOT
parent 3059d66925
commit 812c1895c7
8 changed files with 133 additions and 90 deletions
-9
View File
@@ -239,15 +239,6 @@ extern "C" {
#define RV_READ_MSTATUS_AND_DISABLE_INTR() ({ unsigned long __tmp; \
asm volatile ("csrrci %0, mstatus, 0x8" : "=r"(__tmp)); __tmp; })
#if __riscv_zcmp && SOC_CPU_ZCMP_WORKAROUND
#define RV_READ_MINTTHRESH_AND_DISABLE_INTR() ({ unsigned long __tmp; \
asm volatile ( \
"li t0, 0xff\n\t" \
"csrrw %0, %1, t0" : "=r"(__tmp) : "i"(MINTTHRESH_CSR) : "t0", "memory"); __tmp; })
#define RV_RESTORE_MINTTHRESH(val) \
asm volatile ("csrw %0, %1" :: "i"(MINTTHRESH_CSR), "r"(val) : "memory")
#endif
#define _CSR_STRINGIFY(REG) #REG /* needed so the 'reg' argument can be a macro or a register name */
+44 -1
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -17,6 +17,10 @@
#include "riscv/csr_dsp.h"
#include "sdkconfig.h"
#if __riscv_zcmp && SOC_CPU_ZCMP_WORKAROUND
#include "esp_private/interrupt_clic.h"
#endif
#if CONFIG_SECURE_ENABLE_TEE && !NON_OS_BUILD
#include "secure_service_num.h"
#endif
@@ -167,15 +171,50 @@ FORCE_INLINE_ATTR void rv_utils_set_xtvec(uint32_t xtvec_val)
// ------------------ Interrupt Control --------------------
#if __riscv_zcmp && SOC_CPU_ZCMP_WORKAROUND
extern uint32_t g_xintthresh[SOC_CPU_CORES_NUM];
FORCE_INLINE_ATTR void rv_utils_xintthres_raise(void)
{
/**
* Make sure NOT to use `g_xintthresh[rv_utils_get_core_id()] = rv_utils_set_intlevel_regval(0xff);`
* since that statement would let the compiler first calculate the offset in `g_xintthresh` array
* before setting the interrupt threshold, which may lead to a race condition if an interrupt occurs in between.
*/
uint32_t threshold = rv_utils_set_intlevel_regval(0xff);
g_xintthresh[rv_utils_get_core_id()] = threshold;
}
FORCE_INLINE_ATTR void rv_utils_xintthres_lower(void)
{
rv_utils_restore_intlevel_regval(g_xintthresh[rv_utils_get_core_id()]);
}
#else
FORCE_INLINE_ATTR void rv_utils_xintthres_raise(void)
{
}
FORCE_INLINE_ATTR void rv_utils_xintthres_lower(void)
{
}
#endif // __riscv_zcmp && SOC_CPU_ZCMP_WORKAROUND
FORCE_INLINE_ATTR void rv_utils_intr_enable(uint32_t intr_mask)
{
#if CONFIG_SECURE_ENABLE_TEE && !NON_OS_BUILD
esp_tee_intr_sec_srv_cb(2, SS_RV_UTILS_INTR_ENABLE, intr_mask);
#else
// Disable all interrupts to make updating of the interrupt mask atomic.
rv_utils_xintthres_raise();
unsigned old_mstatus = RV_CLEAR_CSR(mstatus, MSTATUS_MIE);
esprv_int_enable(intr_mask);
RV_SET_CSR(mstatus, old_mstatus & MSTATUS_MIE);
rv_utils_xintthres_lower();
#endif
}
@@ -185,9 +224,11 @@ FORCE_INLINE_ATTR void rv_utils_intr_disable(uint32_t intr_mask)
esp_tee_intr_sec_srv_cb(2, SS_RV_UTILS_INTR_DISABLE, intr_mask);
#else
// Disable all interrupts to make updating of the interrupt mask atomic.
rv_utils_xintthres_raise();
unsigned old_mstatus = RV_CLEAR_CSR(mstatus, MSTATUS_MIE);
esprv_int_disable(intr_mask);
RV_SET_CSR(mstatus, old_mstatus & MSTATUS_MIE);
rv_utils_xintthres_lower();
#endif
}
@@ -198,10 +239,12 @@ FORCE_INLINE_ATTR void rv_utils_intr_global_enable(void)
#else
RV_SET_CSR(mstatus, MSTATUS_MIE);
#endif
rv_utils_xintthres_lower();
}
FORCE_INLINE_ATTR void rv_utils_intr_global_disable(void)
{
rv_utils_xintthres_raise();
#if CONFIG_SECURE_ENABLE_TEE
if (IS_PRV_M_MODE()) {
RV_CLEAR_CSR(mstatus, MSTATUS_MIE);
+10 -1
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -7,7 +7,16 @@
#include "riscv/rv_utils.h"
#include "hal/interrupt_clic_ll.h"
#include "esp_private/interrupt_clic.h"
#include "esp_attr.h"
#if __riscv_zcmp && SOC_CPU_ZCMP_WORKAROUND
/* Due to a hardware bug, the interrupt threshold must be saved before disabling the interrupts.
* Make sure the array is always accessible. */
#if CONFIG_IDF_TARGET_ESP32P4
SPM_DRAM_ATTR
#endif
uint32_t g_xintthresh[SOC_CPU_CORES_NUM];
#endif
void intr_matrix_route(int intr_src, int intr_num)
{
+2 -2
View File
@@ -184,8 +184,8 @@
.macro mintthresh_csr_disable reg
#if __riscv_zcmp && SOC_CPU_ZCMP_WORKAROUND
/* Workaround for triggering an interrupt even when mstatus.mie is 0, when cm.push is called. */
li t0, 0xff
csrrw \reg, MINTTHRESH_CSR, t0
li \reg, 0xff
csrrw \reg, MINTTHRESH_CSR, \reg
#endif
.endm