diff --git a/components/esp_system/include/esp_private/panic_internal.h b/components/esp_system/include/esp_private/panic_internal.h index d9fadc3360..3cb356f54c 100644 --- a/components/esp_system/include/esp_private/panic_internal.h +++ b/components/esp_system/include/esp_private/panic_internal.h @@ -88,6 +88,8 @@ uint32_t panic_get_cause(const void* frame); void panic_prepare_frame_from_ctx(void* frame); +void panic_clear_active_interrupts(const void* frame); + #ifdef __cplusplus } #endif diff --git a/components/esp_system/panic.c b/components/esp_system/panic.c index e9defe2006..4e0afbe5c9 100644 --- a/components/esp_system/panic.c +++ b/components/esp_system/panic.c @@ -391,6 +391,9 @@ void esp_panic_handler(panic_info_t *info) PANIC_INFO_DUMP(info, state); panic_print_str("\r\n"); + // Now, after all panic info was printed we can clear active interrupts + panic_clear_active_interrupts(info->frame); + /* No matter if we come here from abort or an exception, this variable must be reset. * Else, any exception/error occurring during the current panic handler would considered * an abort. Do this after PANIC_INFO_DUMP(info, state) as it also checks this variable. diff --git a/components/esp_system/port/arch/riscv/panic_arch.c b/components/esp_system/port/arch/riscv/panic_arch.c index 78040cffe4..e76942d93a 100644 --- a/components/esp_system/port/arch/riscv/panic_arch.c +++ b/components/esp_system/port/arch/riscv/panic_arch.c @@ -374,3 +374,10 @@ void panic_prepare_frame_from_ctx(void* frame) ((RvExcFrame *)frame)->mhartid = RV_READ_CSR(mhartid); } + +void panic_clear_active_interrupts(const void *frame) +{ + if (((RvExcFrame *)frame)->mcause == ETS_CACHEERR_INUM) { + esp_cache_err_clear_active_err(); + } +} diff --git a/components/esp_system/port/arch/xtensa/panic_arch.c b/components/esp_system/port/arch/xtensa/panic_arch.c index 89656c284d..078e1609a2 100644 --- a/components/esp_system/port/arch/xtensa/panic_arch.c +++ b/components/esp_system/port/arch/xtensa/panic_arch.c @@ -343,3 +343,9 @@ void panic_prepare_frame_from_ctx(void* frame) /* Nothing to cleanup on xtensa */ (void)frame; } + +void panic_clear_active_interrupts(const void *frame) +{ + /* Nothing to cleanup on xtensa */ + (void)frame; +} diff --git a/components/esp_system/port/include/private/esp_private/cache_err_int.h b/components/esp_system/port/include/private/esp_private/cache_err_int.h index c359ea7d5a..a1c1acfe5a 100644 --- a/components/esp_system/port/include/private/esp_private/cache_err_int.h +++ b/components/esp_system/port/include/private/esp_private/cache_err_int.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -58,6 +58,12 @@ void esp_cache_err_get_panic_info(esp_cache_err_info_t *err_info); */ bool esp_cache_err_has_active_err(void); +/** + * @brief Clear any cache errors interrupt + * + */ +void esp_cache_err_clear_active_err(void); + #if SOC_CACHE_ACS_INVALID_STATE_ON_PANIC /** * @brief Saves and clears active access errors diff --git a/components/esp_system/port/soc/esp32c2/cache_err_int.c b/components/esp_system/port/soc/esp32c2/cache_err_int.c index 24f264eef1..a674d40a4a 100644 --- a/components/esp_system/port/soc/esp32c2/cache_err_int.c +++ b/components/esp_system/port/soc/esp32c2/cache_err_int.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -134,6 +134,12 @@ bool esp_cache_err_has_active_err(void) return cache_ll_l1_get_access_error_intr_status(0, CACHE_LL_L1_ACCESS_EVENT_MASK) || cache_ll_l1_get_illegal_error_intr_status(0, CACHE_LL_L1_ILG_EVENT_MASK); } +void esp_cache_err_clear_active_err(void) +{ + cache_ll_l1_clear_access_error_intr(0, CACHE_LL_L1_ACCESS_EVENT_MASK); + cache_ll_l1_clear_illegal_error_intr(0, CACHE_LL_L1_ILG_EVENT_MASK); +} + void esp_cache_err_int_init(void) { const uint32_t core_id = 0; diff --git a/components/esp_system/port/soc/esp32c3/cache_err_int.c b/components/esp_system/port/soc/esp32c3/cache_err_int.c index 2c8e560804..befe0fe4f2 100644 --- a/components/esp_system/port/soc/esp32c3/cache_err_int.c +++ b/components/esp_system/port/soc/esp32c3/cache_err_int.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -134,6 +134,12 @@ bool esp_cache_err_has_active_err(void) return cache_ll_l1_get_access_error_intr_status(0, CACHE_LL_L1_ACCESS_EVENT_MASK) || cache_ll_l1_get_illegal_error_intr_status(0, CACHE_LL_L1_ILG_EVENT_MASK); } +void esp_cache_err_clear_active_err(void) +{ + cache_ll_l1_clear_access_error_intr(0, CACHE_LL_L1_ACCESS_EVENT_MASK); + cache_ll_l1_clear_illegal_error_intr(0, CACHE_LL_L1_ILG_EVENT_MASK); +} + void esp_cache_err_int_init(void) { const uint32_t core_id = 0; diff --git a/components/esp_system/port/soc/esp32c5/cache_err_int.c b/components/esp_system/port/soc/esp32c5/cache_err_int.c index 10f0cdd45a..96b8447a04 100644 --- a/components/esp_system/port/soc/esp32c5/cache_err_int.c +++ b/components/esp_system/port/soc/esp32c5/cache_err_int.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -40,6 +40,11 @@ bool esp_cache_err_has_active_err(void) return cache_ll_l1_get_access_error_intr_status(0, CACHE_LL_L1_ACCESS_EVENT_MASK); } +void esp_cache_err_clear_active_err(void) +{ + cache_ll_l1_clear_access_error_intr(0, CACHE_LL_L1_ACCESS_EVENT_MASK); +} + void esp_cache_err_int_init(void) { const uint32_t core_id = 0; diff --git a/components/esp_system/port/soc/esp32c6/cache_err_int.c b/components/esp_system/port/soc/esp32c6/cache_err_int.c index 5cc77ed1ac..b254e34bfe 100644 --- a/components/esp_system/port/soc/esp32c6/cache_err_int.c +++ b/components/esp_system/port/soc/esp32c6/cache_err_int.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -39,6 +39,11 @@ bool esp_cache_err_has_active_err(void) return cache_ll_l1_get_access_error_intr_status(0, CACHE_LL_L1_ACCESS_EVENT_MASK); } +void esp_cache_err_clear_active_err(void) +{ + cache_ll_l1_clear_access_error_intr(0, CACHE_LL_L1_ACCESS_EVENT_MASK); +} + void esp_cache_err_int_init(void) { const uint32_t core_id = 0; diff --git a/components/esp_system/port/soc/esp32c61/cache_err_int.c b/components/esp_system/port/soc/esp32c61/cache_err_int.c index 7dd5661632..b180395065 100644 --- a/components/esp_system/port/soc/esp32c61/cache_err_int.c +++ b/components/esp_system/port/soc/esp32c61/cache_err_int.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -39,6 +39,11 @@ bool esp_cache_err_has_active_err(void) return cache_ll_l1_get_access_error_intr_status(0, CACHE_LL_L1_ACCESS_EVENT_MASK); } +void esp_cache_err_clear_active_err(void) +{ + cache_ll_l1_clear_access_error_intr(0, CACHE_LL_L1_ACCESS_EVENT_MASK); +} + void esp_cache_err_int_init(void) { const uint32_t core_id = 0; diff --git a/components/esp_system/port/soc/esp32h2/cache_err_int.c b/components/esp_system/port/soc/esp32h2/cache_err_int.c index e4b0b03d4f..e9758a320e 100644 --- a/components/esp_system/port/soc/esp32h2/cache_err_int.c +++ b/components/esp_system/port/soc/esp32h2/cache_err_int.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -39,6 +39,11 @@ bool esp_cache_err_has_active_err(void) return cache_ll_l1_get_access_error_intr_status(0, CACHE_LL_L1_ACCESS_EVENT_MASK); } +void esp_cache_err_clear_active_err(void) +{ + cache_ll_l1_clear_access_error_intr(0, CACHE_LL_L1_ACCESS_EVENT_MASK); +} + void esp_cache_err_int_init(void) { const uint32_t core_id = 0; diff --git a/components/esp_system/port/soc/esp32h21/cache_err_int.c b/components/esp_system/port/soc/esp32h21/cache_err_int.c index 4b9d86e859..75e0b5b512 100644 --- a/components/esp_system/port/soc/esp32h21/cache_err_int.c +++ b/components/esp_system/port/soc/esp32h21/cache_err_int.c @@ -39,6 +39,11 @@ bool esp_cache_err_has_active_err(void) return cache_ll_l1_get_access_error_intr_status(0, CACHE_LL_L1_ACCESS_EVENT_MASK); } +void esp_cache_err_clear_active_err(void) +{ + cache_ll_l1_clear_access_error_intr(0, CACHE_LL_L1_ACCESS_EVENT_MASK); +} + void esp_cache_err_int_init(void) { const uint32_t core_id = 0; diff --git a/components/esp_system/port/soc/esp32h4/cache_err_int.c b/components/esp_system/port/soc/esp32h4/cache_err_int.c index 7a598319e9..827b9cff64 100644 --- a/components/esp_system/port/soc/esp32h4/cache_err_int.c +++ b/components/esp_system/port/soc/esp32h4/cache_err_int.c @@ -39,6 +39,11 @@ bool esp_cache_err_has_active_err(void) return cache_ll_l1_get_access_error_intr_status(0, CACHE_LL_L1_ACCESS_EVENT_MASK); } +void esp_cache_err_clear_active_err(void) +{ + cache_ll_l1_clear_access_error_intr(0, CACHE_LL_L1_ACCESS_EVENT_MASK); +} + void esp_cache_err_int_init(void) { const uint32_t core_id = 0; diff --git a/components/esp_system/port/soc/esp32p4/cache_err_int.c b/components/esp_system/port/soc/esp32p4/cache_err_int.c index 8bd4960f5f..3abe9015fb 100644 --- a/components/esp_system/port/soc/esp32p4/cache_err_int.c +++ b/components/esp_system/port/soc/esp32p4/cache_err_int.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -41,6 +41,12 @@ bool esp_cache_err_has_active_err(void) return has_active_err; } +void esp_cache_err_clear_active_err(void) +{ + cache_ll_l1_clear_access_error_intr(0, CACHE_LL_L1_ACCESS_EVENT_MASK); + cache_ll_l2_clear_access_error_intr(0, CACHE_LL_L2_ACCESS_EVENT_MASK); +} + void esp_cache_err_int_init(void) { const uint32_t core_id = 0; diff --git a/components/esp_tee/CMakeLists.txt b/components/esp_tee/CMakeLists.txt index fd39d792bf..bd104f5911 100644 --- a/components/esp_tee/CMakeLists.txt +++ b/components/esp_tee/CMakeLists.txt @@ -15,7 +15,6 @@ endif() if(BOOTLOADER_BUILD) idf_component_register() - return() elseif(esp_tee_build) # TEE build currently only uses the shared headers. idf_component_register(INCLUDE_DIRS include) @@ -86,6 +85,20 @@ else() endif() endif() +# TODO: IDF-14145 +if((CONFIG_SECURE_ENABLE_TEE OR esp_tee_build) AND CMAKE_C_COMPILER_ID MATCHES "GNU") + if(CONFIG_IDF_TARGET_ESP32C5 OR CONFIG_IDF_TARGET_ESP32C61) + # Disable zcmp extension to avoid hardware issue with interrupts (DIG-661) + set(march_option "-march=rv32imac_zicsr_zifencei_zaamo_zalrsc") + idf_build_set_property(COMPILE_OPTIONS "${march_option}" APPEND) + idf_build_set_property(LINK_OPTIONS "${march_option}" APPEND) + endif() +endif() + +if(BOOTLOADER_BUILD) + return() +endif() + set(secure_service_yml ${COMPONENT_DIR}/scripts/${IDF_TARGET}/sec_srv_tbl_default.yml ${custom_secure_service_yaml} ) diff --git a/components/esp_wifi/test_apps/bin_size_apsta/pytest_bin_size_apsta.py b/components/esp_wifi/test_apps/bin_size_apsta/pytest_bin_size_apsta.py index 51e16ecac6..0aafd1c7eb 100644 --- a/components/esp_wifi/test_apps/bin_size_apsta/pytest_bin_size_apsta.py +++ b/components/esp_wifi/test_apps/bin_size_apsta/pytest_bin_size_apsta.py @@ -1,8 +1,7 @@ # SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Unlicense OR CC0-1.0 import os -from typing import Callable -from typing import Tuple +from collections.abc import Callable import pytest from pytest_embedded import Dut @@ -14,17 +13,17 @@ SAVE_BIN_SIZE_TH = { 'esp32': 16600, 'esp32c2': 19700, 'esp32c3': 19600, - 'esp32c5': 19650, + 'esp32c5': 17800, 'esp32c6': 19650, - 'esp32c61': 19700, + 'esp32c61': 17800, 'esp32s2': 16600, 'esp32s3': 16550, 'default': 16000, }, 'disable_nan': { 'esp32': 29600, - 'esp32c5': 32000, - 'esp32c61': 32000, + 'esp32c5': 31700, + 'esp32c61': 31600, 'esp32s2': 28000, # other chips does not support nan 'default': 0, @@ -56,8 +55,8 @@ def _get_diff_th( indirect=['target'], ) def test_wifi_bin_size_apsta( - dut: Tuple[Dut, Dut], - config: Tuple[str, str], + dut: tuple[Dut, Dut], + config: tuple[str, str], log_performance: Callable[[str, object], None], ) -> None: # dut logs are not needed diff --git a/components/hal/test_apps/tee/main/CMakeLists.txt b/components/hal/test_apps/tee/main/CMakeLists.txt index 4e96a101a4..a701218c2c 100644 --- a/components/hal/test_apps/tee/main/CMakeLists.txt +++ b/components/hal/test_apps/tee/main/CMakeLists.txt @@ -7,3 +7,11 @@ idf_component_register(SRCS "${srcs}" INCLUDE_DIRS "" PRIV_REQUIRES pms_and_cpu_intr esp_psram WHOLE_ARCHIVE) + +# TODO: IDF-14145 +if(CONFIG_IDF_TARGET_ESP32C5 OR CONFIG_IDF_TARGET_ESP32C61) + # Disable zcmp extension to avoid hardware issue with interrupts (DIG-661) + set(march_option "-march=rv32imac_zicsr_zifencei_zaamo_zalrsc") + idf_build_set_property(COMPILE_OPTIONS "${march_option}" APPEND) + idf_build_set_property(LINK_OPTIONS "${march_option}" APPEND) +endif() diff --git a/components/riscv/include/esp_private/interrupt_clic.h b/components/riscv/include/esp_private/interrupt_clic.h index e5aed509e6..89fee96c5d 100644 --- a/components/riscv/include/esp_private/interrupt_clic.h +++ b/components/riscv/include/esp_private/interrupt_clic.h @@ -12,6 +12,7 @@ #include "soc/soc_caps.h" #include "esp_attr.h" #include "riscv/csr.h" +#include "riscv/csr_clic.h" #if SOC_INT_CLIC_SUPPORTED @@ -21,102 +22,6 @@ extern "C" { #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 #define IS_PRV_M_MODE() (RV_READ_CSR(CSR_PRV_MODE) == PRV_M) #else diff --git a/components/riscv/include/riscv/csr_clic.h b/components/riscv/include/riscv/csr_clic.h new file mode 100644 index 0000000000..a174954f7d --- /dev/null +++ b/components/riscv/include/riscv/csr_clic.h @@ -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 */ diff --git a/components/riscv/vectors.S b/components/riscv/vectors.S index 114f83a41c..d7e822869c 100644 --- a/components/riscv/vectors.S +++ b/components/riscv/vectors.S @@ -5,7 +5,7 @@ */ #include "soc/soc.h" -#include "soc/interrupt_reg.h" +#include "riscv/csr_clic.h" #include "riscv/rvruntime-frames.h" #include "soc/soc_caps.h" #include "sdkconfig.h" @@ -181,6 +181,20 @@ #endif .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 #if CONFIG_SECURE_ENABLE_TEE uret @@ -216,6 +230,8 @@ _panic_handler: /* Allocate space on the stack and store general purpose registers */ save_general_regs RV_STK_FRMSZ + mintthresh_csr_disable s5 + /* As gp register is not saved by the macro, save it here */ sw gp, RV_STK_GP(sp) @@ -366,6 +382,8 @@ _store_mcause: * Restore the registers and return from the exception. */ _return_from_exception: + mintthresh_csr_restore s5 + restore_xepc /* MTVEC and SP are assumed to be unmodified. * 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 */ + mintthresh_csr_disable s5 + disable_intr /* MIE cleared. Nested interrupts are disabled */ @@ -510,6 +530,9 @@ _skip_thresh_reset: csrw mcause, s1 csrw mstatus, a0 #endif + + mintthresh_csr_restore s5 + restore_xepc restore_general_regs /* exit, this will also re-enable the interrupts */ diff --git a/components/soc/esp32c5/include/soc/interrupt_reg.h b/components/soc/esp32c5/include/soc/interrupt_reg.h index 74cf892ebe..b14126d56a 100644 --- a/components/soc/esp32c5/include/soc/interrupt_reg.h +++ b/components/soc/esp32c5/include/soc/interrupt_reg.h @@ -19,6 +19,8 @@ extern "C" { /* We only have a single core on the C5, CORE0 */ #define INTERRUPT_CORE0_CPU_INT_THRESH_REG INTERRUPT_CURRENT_CORE_INT_THRESH_REG +#define INTTHRESH_STANDARD 1 + #ifdef __cplusplus } #endif diff --git a/components/soc/esp32c61/include/soc/interrupt_reg.h b/components/soc/esp32c61/include/soc/interrupt_reg.h index d94be8a2ae..472e2aa977 100644 --- a/components/soc/esp32c61/include/soc/interrupt_reg.h +++ b/components/soc/esp32c61/include/soc/interrupt_reg.h @@ -14,3 +14,5 @@ #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 INTTHRESH_STANDARD 1 diff --git a/components/soc/esp32h4/include/soc/interrupt_reg.h b/components/soc/esp32h4/include/soc/interrupt_reg.h index 510603d190..c7c79a0883 100644 --- a/components/soc/esp32h4/include/soc/interrupt_reg.h +++ b/components/soc/esp32h4/include/soc/interrupt_reg.h @@ -12,3 +12,5 @@ #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 INTTHRESH_STANDARD 1 diff --git a/components/soc/esp32p4/include/soc/interrupt_reg.h b/components/soc/esp32p4/include/soc/interrupt_reg.h index 1eb016ab24..60e9481a21 100644 --- a/components/soc/esp32p4/include/soc/interrupt_reg.h +++ b/components/soc/esp32p4/include/soc/interrupt_reg.h @@ -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 */ @@ -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_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 } #endif diff --git a/tools/cmake/toolchain-esp32c5.cmake b/tools/cmake/toolchain-esp32c5.cmake index 99e8281713..597f7f0df9 100644 --- a/tools/cmake/toolchain-esp32c5.cmake +++ b/tools/cmake/toolchain-esp32c5.cmake @@ -7,7 +7,8 @@ set(CMAKE_CXX_COMPILER riscv32-esp-elf-g++) set(CMAKE_ASM_COMPILER riscv32-esp-elf-gcc) set(_CMAKE_TOOLCHAIN_PREFIX riscv32-esp-elf-) -set(_CMAKE_TOOLCHAIN_COMMON_FLAGS "-march=rv32imac_zicsr_zifencei_zaamo_zalrsc") +set(_CMAKE_TOOLCHAIN_COMMON_FLAGS "-march=rv32imac_zicsr_zifencei_zaamo_zalrsc_zcb_zcmp_zcmt \ + -mno-cm-popret -mno-cm-push-reverse") remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} -mtune=esp-base ${CMAKE_C_FLAGS}" UNIQ_CMAKE_C_FLAGS) set(CMAKE_C_FLAGS "${UNIQ_CMAKE_C_FLAGS}" CACHE STRING "C Compiler Base Flags" FORCE) diff --git a/tools/cmake/toolchain-esp32c61.cmake b/tools/cmake/toolchain-esp32c61.cmake index 99e8281713..597f7f0df9 100644 --- a/tools/cmake/toolchain-esp32c61.cmake +++ b/tools/cmake/toolchain-esp32c61.cmake @@ -7,7 +7,8 @@ set(CMAKE_CXX_COMPILER riscv32-esp-elf-g++) set(CMAKE_ASM_COMPILER riscv32-esp-elf-gcc) set(_CMAKE_TOOLCHAIN_PREFIX riscv32-esp-elf-) -set(_CMAKE_TOOLCHAIN_COMMON_FLAGS "-march=rv32imac_zicsr_zifencei_zaamo_zalrsc") +set(_CMAKE_TOOLCHAIN_COMMON_FLAGS "-march=rv32imac_zicsr_zifencei_zaamo_zalrsc_zcb_zcmp_zcmt \ + -mno-cm-popret -mno-cm-push-reverse") remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} -mtune=esp-base ${CMAKE_C_FLAGS}" UNIQ_CMAKE_C_FLAGS) set(CMAKE_C_FLAGS "${UNIQ_CMAKE_C_FLAGS}" CACHE STRING "C Compiler Base Flags" FORCE) diff --git a/tools/cmake/toolchain-esp32h4.cmake b/tools/cmake/toolchain-esp32h4.cmake index 36fbc09076..10cfa96f58 100644 --- a/tools/cmake/toolchain-esp32h4.cmake +++ b/tools/cmake/toolchain-esp32h4.cmake @@ -7,7 +7,9 @@ set(CMAKE_CXX_COMPILER riscv32-esp-elf-g++) set(CMAKE_ASM_COMPILER riscv32-esp-elf-gcc) set(_CMAKE_TOOLCHAIN_PREFIX riscv32-esp-elf-) -set(_CMAKE_TOOLCHAIN_COMMON_FLAGS "-march=rv32imafc_zicsr_zifencei_zaamo_zalrsc_xespdsp -mabi=ilp32f") +set(_CMAKE_TOOLCHAIN_COMMON_FLAGS "-march=rv32imafcb_zicsr_zifencei_zaamo_zalrsc_zcb_zcmp_zcmt_zba_zbb_zbs_xespdsp \ + -mabi=ilp32f \ + -mno-cm-popret -mno-cm-push-reverse") remove_duplicated_flags("${_CMAKE_TOOLCHAIN_COMMON_FLAGS} -mtune=esp-base ${CMAKE_C_FLAGS}" UNIQ_CMAKE_C_FLAGS) set(CMAKE_C_FLAGS "${UNIQ_CMAKE_C_FLAGS}" CACHE STRING "C Compiler Base Flags" FORCE)