diff --git a/components/esp_system/port/soc/esp32c5/system_internal.c b/components/esp_system/port/soc/esp32c5/system_internal.c index 83228327566..1ab861d269c 100644 --- a/components/esp_system/port/soc/esp32c5/system_internal.c +++ b/components/esp_system/port/soc/esp32c5/system_internal.c @@ -29,6 +29,10 @@ #include "hal/modem_lpcon_ll.h" #endif #include "esp_private/cache_err_int.h" +#include "esp_memory_utils.h" + +#define ALIGN_DOWN(val, align) ((val) & ~((align) - 1)) +extern int _bss_end; #include "esp32c5/rom/cache.h" #include "esp32c5/rom/rtc.h" @@ -101,6 +105,24 @@ void esp_system_reset_modules_on_exit(void) uart_ll_sclk_enable(&UART0); } +static void IRAM_ATTR __attribute__((noinline, noreturn)) esp_restart_noos_inner(void) +{ + // Disable cache + Cache_Disable_Cache(); + + esp_system_reset_modules_on_exit(); + + // Set CPU back to XTAL source, same as hard reset, but keep BBPLL on so that USB Serial JTAG can log at 1st stage bootloader. +#if !CONFIG_IDF_ENV_FPGA + rtc_clk_cpu_set_to_default_config(); +#endif + + // Reset PRO CPU + esp_rom_software_reset_cpu(0); + + ESP_INFINITE_LOOP(); +} + /* "inner" restart function for after RTOS, interrupts & anything else on this * core are already stopped. Stalls other core, resets hardware, * triggers restart. @@ -137,18 +159,15 @@ void esp_restart_noos(void) wdt_hal_write_protect_enable(&wdt1_context); #endif /* SOC_WDT_SUPPORTED */ - // Disable cache - Cache_Disable_Cache(); - - esp_system_reset_modules_on_exit(); - - // Set CPU back to XTAL source, same as hard reset, but keep BBPLL on so that USB Serial JTAG can log at 1st stage bootloader. -#if !CONFIG_IDF_ENV_FPGA - rtc_clk_cpu_set_to_default_config(); +#ifdef CONFIG_FREERTOS_TASK_CREATE_ALLOW_EXT_MEM + if (esp_ptr_external_ram(esp_cpu_get_sp())) { + // If stack is in external RAM (CONFIG_FREERTOS_TASK_CREATE_ALLOW_EXT_MEM), switch SP to + // internal RAM before disabling the cache to avoid a "Cache disabled but cached memory + // region accessed" crash. + uint32_t new_sp = ALIGN_DOWN((uint32_t)&_bss_end, 16); + rv_utils_set_sp((void *)new_sp); + } #endif - // Reset PRO CPU - esp_rom_software_reset_cpu(0); - - ESP_INFINITE_LOOP(); + esp_restart_noos_inner(); } diff --git a/components/esp_system/port/soc/esp32c61/system_internal.c b/components/esp_system/port/soc/esp32c61/system_internal.c index 02a3ec8b9b4..5e703bc3927 100644 --- a/components/esp_system/port/soc/esp32c61/system_internal.c +++ b/components/esp_system/port/soc/esp32c61/system_internal.c @@ -26,6 +26,10 @@ #endif #include "hal/uart_ll.h" #include "esp_private/cache_err_int.h" +#include "esp_memory_utils.h" + +#define ALIGN_DOWN(val, align) ((val) & ~((align) - 1)) +extern int _bss_end; #if SOC_MODEM_CLOCK_SUPPORTED #include "hal/modem_syscon_ll.h" @@ -102,6 +106,23 @@ void esp_system_reset_modules_on_exit(void) uart_ll_sclk_enable(&UART0); } +static void IRAM_ATTR __attribute__((noinline, noreturn)) esp_restart_noos_inner(void) +{ + // Disable cache + Cache_Disable_Cache(); + + esp_system_reset_modules_on_exit(); + + // Set CPU back to XTAL source, same as hard reset, but keep BBPLL on so that USB Serial JTAG can log at 1st stage bootloader. +#if !CONFIG_IDF_ENV_FPGA + rtc_clk_cpu_set_to_default_config(); +#endif + + // Reset PRO CPU + esp_rom_software_reset_cpu(0); + ESP_INFINITE_LOOP(); +} + /* "inner" restart function for after RTOS, interrupts & anything else on this * core are already stopped. Stalls other core, resets hardware, * triggers restart. @@ -138,17 +159,15 @@ void esp_restart_noos(void) wdt_hal_write_protect_enable(&wdt1_context); #endif /* SOC_WDT_SUPPORTED */ - // Disable cache - Cache_Disable_Cache(); - - esp_system_reset_modules_on_exit(); - - // Set CPU back to XTAL source, same as hard reset, but keep BBPLL on so that USB Serial JTAG can log at 1st stage bootloader. -#if !CONFIG_IDF_ENV_FPGA - rtc_clk_cpu_set_to_default_config(); +#ifdef CONFIG_FREERTOS_TASK_CREATE_ALLOW_EXT_MEM + if (esp_ptr_external_ram(esp_cpu_get_sp())) { + // If stack is in external RAM (CONFIG_FREERTOS_TASK_CREATE_ALLOW_EXT_MEM), switch SP to + // internal RAM before disabling the cache to avoid a "Cache disabled but cached memory + // region accessed" crash. + uint32_t new_sp = ALIGN_DOWN((uint32_t)&_bss_end, 16); + rv_utils_set_sp((void *)new_sp); + } #endif - // Reset PRO CPU - esp_rom_software_reset_cpu(0); - ESP_INFINITE_LOOP(); + esp_restart_noos_inner(); } diff --git a/components/esp_system/port/soc/esp32h4/system_internal.c b/components/esp_system/port/soc/esp32h4/system_internal.c index bab0dd57698..9b765e5843a 100644 --- a/components/esp_system/port/soc/esp32h4/system_internal.c +++ b/components/esp_system/port/soc/esp32h4/system_internal.c @@ -24,6 +24,10 @@ #include "hal/wdt_hal.h" #endif #include "hal/uart_ll.h" +#include "esp_memory_utils.h" + +#define ALIGN_DOWN(val, align) ((val) & ~((align) - 1)) +extern int _bss_end; #include "esp32h4/rom/cache.h" #include "esp32h4/rom/ets_sys.h" @@ -87,46 +91,9 @@ void esp_system_reset_modules_on_exit(void) uart_ll_sclk_enable(&UART0); } -/* "inner" restart function for after RTOS, interrupts & anything else on this - * core are already stopped. Stalls other core, resets hardware, - * triggers restart. -*/ -void esp_restart_noos(void) +static void IRAM_ATTR __attribute__((noinline, noreturn)) esp_restart_noos_inner(void) { - // Disable interrupts - rv_utils_intr_global_disable(); -#if SOC_RTC_WDT_SUPPORTED - // Enable RTC watchdog for 1 second - wdt_hal_context_t rtc_wdt_ctx; - wdt_hal_init(&rtc_wdt_ctx, WDT_RWDT, 0, false); - uint32_t stage_timeout_ticks = (uint32_t)(1000ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); - wdt_hal_write_protect_disable(&rtc_wdt_ctx); - wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_SYSTEM); - wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE1, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); - //Enable flash boot mode so that flash booting after restart is protected by the RTC WDT. - wdt_hal_set_flashboot_en(&rtc_wdt_ctx, true); - wdt_hal_write_protect_enable(&rtc_wdt_ctx); -#endif /* SOC_RTC_WDT_SUPPORTED */ - const uint32_t core_id = esp_cpu_get_core_id(); -#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE - const uint32_t other_core_id = (core_id == 0) ? 1 : 0; - esp_cpu_reset(other_core_id); - esp_cpu_stall(other_core_id); -#endif - -#if SOC_WDT_SUPPORTED - // Disable TG0/TG1 watchdogs - wdt_hal_context_t wdt0_context = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0}; - wdt_hal_write_protect_disable(&wdt0_context); - wdt_hal_disable(&wdt0_context); - wdt_hal_write_protect_enable(&wdt0_context); - - wdt_hal_context_t wdt1_context = {.inst = WDT_MWDT1, .mwdt_dev = &TIMERG1}; - wdt_hal_write_protect_disable(&wdt1_context); - wdt_hal_disable(&wdt1_context); - wdt_hal_write_protect_enable(&wdt1_context); -#endif /* SOC_WDT_SUPPORTED */ // Disable cache Cache_Disable_Cache(CACHE_MAP_ALL); @@ -162,3 +129,57 @@ void esp_restart_noos(void) #endif ESP_INFINITE_LOOP(); } + +/* "inner" restart function for after RTOS, interrupts & anything else on this + * core are already stopped. Stalls other core, resets hardware, + * triggers restart. +*/ +void esp_restart_noos(void) +{ + // Disable interrupts + rv_utils_intr_global_disable(); +#if SOC_RTC_WDT_SUPPORTED + // Enable RTC watchdog for 1 second + wdt_hal_context_t rtc_wdt_ctx; + wdt_hal_init(&rtc_wdt_ctx, WDT_RWDT, 0, false); + uint32_t stage_timeout_ticks = (uint32_t)(1000ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_SYSTEM); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE1, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); + //Enable flash boot mode so that flash booting after restart is protected by the RTC WDT. + wdt_hal_set_flashboot_en(&rtc_wdt_ctx, true); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); +#endif /* SOC_RTC_WDT_SUPPORTED */ + +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE + const uint32_t core_id = esp_cpu_get_core_id(); + const uint32_t other_core_id = (core_id == 0) ? 1 : 0; + esp_cpu_reset(other_core_id); + esp_cpu_stall(other_core_id); +#endif + +#if SOC_WDT_SUPPORTED + // Disable TG0/TG1 watchdogs + wdt_hal_context_t wdt0_context = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0}; + wdt_hal_write_protect_disable(&wdt0_context); + wdt_hal_disable(&wdt0_context); + wdt_hal_write_protect_enable(&wdt0_context); + + wdt_hal_context_t wdt1_context = {.inst = WDT_MWDT1, .mwdt_dev = &TIMERG1}; + wdt_hal_write_protect_disable(&wdt1_context); + wdt_hal_disable(&wdt1_context); + wdt_hal_write_protect_enable(&wdt1_context); +#endif /* SOC_WDT_SUPPORTED */ + +#ifdef CONFIG_FREERTOS_TASK_CREATE_ALLOW_EXT_MEM + if (esp_ptr_external_ram(esp_cpu_get_sp())) { + // If stack is in external RAM (CONFIG_FREERTOS_TASK_CREATE_ALLOW_EXT_MEM), switch SP to + // internal RAM before disabling the cache to avoid a "Cache disabled but cached memory + // region accessed" crash. + uint32_t new_sp = ALIGN_DOWN((uint32_t)&_bss_end, 16); + rv_utils_set_sp((void *)new_sp); + } +#endif + + esp_restart_noos_inner(); +} diff --git a/components/esp_system/port/soc/esp32p4/system_internal.c b/components/esp_system/port/soc/esp32p4/system_internal.c index 6e9de0ffc63..5456d680631 100644 --- a/components/esp_system/port/soc/esp32p4/system_internal.c +++ b/components/esp_system/port/soc/esp32p4/system_internal.c @@ -37,6 +37,10 @@ #include "hal/dw_gdma_ll.h" #include "hal/dma2d_ll.h" #include "hal/efuse_hal.h" +#include "esp_memory_utils.h" + +#define ALIGN_DOWN(val, align) ((val) & ~((align) - 1)) +extern int _bss_end; void esp_system_reset_modules_on_exit(void) { @@ -153,46 +157,9 @@ void esp_system_reset_modules_on_exit(void) #endif } -/* "inner" restart function for after RTOS, interrupts & anything else on this - * core are already stopped. Stalls other core, resets hardware, - * triggers restart. -*/ -void esp_restart_noos(void) +static void IRAM_ATTR __attribute__((noinline, noreturn)) esp_restart_noos_inner(void) { - // Disable interrupts - rv_utils_intr_global_disable(); -#if SOC_RTC_WDT_SUPPORTED - // Enable RTC watchdog for 1 second - wdt_hal_context_t rtc_wdt_ctx; - wdt_hal_init(&rtc_wdt_ctx, WDT_RWDT, 0, false); - uint32_t stage_timeout_ticks = (uint32_t)(1000ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); - wdt_hal_write_protect_disable(&rtc_wdt_ctx); - wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_SYSTEM); - wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE1, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); - //Enable flash boot mode so that flash booting after restart is protected by the RTC WDT. - wdt_hal_set_flashboot_en(&rtc_wdt_ctx, true); - wdt_hal_write_protect_enable(&rtc_wdt_ctx); -#endif /* SOC_RTC_WDT_SUPPORTED */ - const uint32_t core_id = esp_cpu_get_core_id(); -#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE - const uint32_t other_core_id = (core_id == 0) ? 1 : 0; - esp_cpu_reset(other_core_id); - esp_cpu_stall(other_core_id); -#endif - -#if SOC_WDT_SUPPORTED - // Disable TG0/TG1 watchdogs - wdt_hal_context_t wdt0_context = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0}; - wdt_hal_write_protect_disable(&wdt0_context); - wdt_hal_disable(&wdt0_context); - wdt_hal_write_protect_enable(&wdt0_context); - - wdt_hal_context_t wdt1_context = {.inst = WDT_MWDT1, .mwdt_dev = &TIMERG1}; - wdt_hal_write_protect_disable(&wdt1_context); - wdt_hal_disable(&wdt1_context); - wdt_hal_write_protect_enable(&wdt1_context); -#endif /* SOC_WDT_SUPPORTED */ // Disable cache #if CONFIG_SPIRAM @@ -237,3 +204,57 @@ void esp_restart_noos(void) ESP_INFINITE_LOOP(); } + +/* "inner" restart function for after RTOS, interrupts & anything else on this + * core are already stopped. Stalls other core, resets hardware, + * triggers restart. +*/ +void esp_restart_noos(void) +{ + // Disable interrupts + rv_utils_intr_global_disable(); +#if SOC_RTC_WDT_SUPPORTED + // Enable RTC watchdog for 1 second + wdt_hal_context_t rtc_wdt_ctx; + wdt_hal_init(&rtc_wdt_ctx, WDT_RWDT, 0, false); + uint32_t stage_timeout_ticks = (uint32_t)(1000ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_SYSTEM); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE1, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); + //Enable flash boot mode so that flash booting after restart is protected by the RTC WDT. + wdt_hal_set_flashboot_en(&rtc_wdt_ctx, true); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); +#endif /* SOC_RTC_WDT_SUPPORTED */ + +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE + const uint32_t core_id = esp_cpu_get_core_id(); + const uint32_t other_core_id = (core_id == 0) ? 1 : 0; + esp_cpu_reset(other_core_id); + esp_cpu_stall(other_core_id); +#endif + +#if SOC_WDT_SUPPORTED + // Disable TG0/TG1 watchdogs + wdt_hal_context_t wdt0_context = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0}; + wdt_hal_write_protect_disable(&wdt0_context); + wdt_hal_disable(&wdt0_context); + wdt_hal_write_protect_enable(&wdt0_context); + + wdt_hal_context_t wdt1_context = {.inst = WDT_MWDT1, .mwdt_dev = &TIMERG1}; + wdt_hal_write_protect_disable(&wdt1_context); + wdt_hal_disable(&wdt1_context); + wdt_hal_write_protect_enable(&wdt1_context); +#endif /* SOC_WDT_SUPPORTED */ + +#ifdef CONFIG_FREERTOS_TASK_CREATE_ALLOW_EXT_MEM + if (esp_ptr_external_ram(esp_cpu_get_sp())) { + // If stack is in external RAM (CONFIG_FREERTOS_TASK_CREATE_ALLOW_EXT_MEM), switch SP to + // internal RAM before disabling the cache to avoid a "Cache disabled but cached memory + // region accessed" crash. + uint32_t new_sp = ALIGN_DOWN((uint32_t)&_bss_end, 16); + rv_utils_set_sp((void *)new_sp); + } +#endif + + esp_restart_noos_inner(); +} diff --git a/components/esp_system/port/soc/esp32s31/system_internal.c b/components/esp_system/port/soc/esp32s31/system_internal.c index bdc656ed639..470bd516425 100644 --- a/components/esp_system/port/soc/esp32s31/system_internal.c +++ b/components/esp_system/port/soc/esp32s31/system_internal.c @@ -26,6 +26,11 @@ #endif #include "esp_private/cache_err_int.h" #include "hal/uart_ll.h" +#include "esp_memory_utils.h" + +#define ALIGN_DOWN(val, align) ((val) & ~((align) - 1)) +extern int _bss_end; + #include "esp32s31/rom/cache.h" #include "esp32s31/rom/ets_sys.h" #include "esp32s31/rom/rtc.h" @@ -45,47 +50,9 @@ void esp_system_reset_modules_on_exit(void) } } -/* "inner" restart function for after RTOS, interrupts & anything else on this - * core are already stopped. Stalls other core, resets hardware, - * triggers restart. -*/ -void esp_restart_noos(void) +static void IRAM_ATTR __attribute__((noinline, noreturn)) esp_restart_noos_inner(void) { - // Disable interrupts - rv_utils_intr_global_disable(); -#if SOC_RTC_WDT_SUPPORTED - // Enable RTC watchdog for 1 second - wdt_hal_context_t rtc_wdt_ctx; - wdt_hal_init(&rtc_wdt_ctx, WDT_RWDT, 0, false); - // uint32_t stage_timeout_ticks = (uint32_t)(1000ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); - uint32_t stage_timeout_ticks = (uint32_t)rtc_clk_slow_freq_get_hz(); - wdt_hal_write_protect_disable(&rtc_wdt_ctx); - wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_SYSTEM); - wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE1, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); - //Enable flash boot mode so that flash booting after restart is protected by the RTC WDT. - wdt_hal_set_flashboot_en(&rtc_wdt_ctx, true); - wdt_hal_write_protect_enable(&rtc_wdt_ctx); -#endif /* SOC_RTC_WDT_SUPPORTED */ - const uint32_t core_id = esp_cpu_get_core_id(); -#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE - const uint32_t other_core_id = (core_id == 0) ? 1 : 0; - esp_cpu_reset(other_core_id); - esp_cpu_stall(other_core_id); -#endif - -#if SOC_WDT_SUPPORTED - // Disable TG0/TG1 watchdogs - wdt_hal_context_t wdt0_context = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0}; - wdt_hal_write_protect_disable(&wdt0_context); - wdt_hal_disable(&wdt0_context); - wdt_hal_write_protect_enable(&wdt0_context); - - wdt_hal_context_t wdt1_context = {.inst = WDT_MWDT1, .mwdt_dev = &TIMERG1}; - wdt_hal_write_protect_disable(&wdt1_context); - wdt_hal_disable(&wdt1_context); - wdt_hal_write_protect_enable(&wdt1_context); -#endif /* SOC_WDT_SUPPORTED */ // Disable cache #if CONFIG_SPIRAM @@ -129,3 +96,58 @@ void esp_restart_noos(void) ESP_INFINITE_LOOP(); } + +/* "inner" restart function for after RTOS, interrupts & anything else on this + * core are already stopped. Stalls other core, resets hardware, + * triggers restart. +*/ +void esp_restart_noos(void) +{ + // Disable interrupts + rv_utils_intr_global_disable(); +#if SOC_RTC_WDT_SUPPORTED + // Enable RTC watchdog for 1 second + wdt_hal_context_t rtc_wdt_ctx; + wdt_hal_init(&rtc_wdt_ctx, WDT_RWDT, 0, false); + // uint32_t stage_timeout_ticks = (uint32_t)(1000ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); + uint32_t stage_timeout_ticks = (uint32_t)rtc_clk_slow_freq_get_hz(); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_SYSTEM); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE1, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); + //Enable flash boot mode so that flash booting after restart is protected by the RTC WDT. + wdt_hal_set_flashboot_en(&rtc_wdt_ctx, true); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); +#endif /* SOC_RTC_WDT_SUPPORTED */ + +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE + const uint32_t core_id = esp_cpu_get_core_id(); + const uint32_t other_core_id = (core_id == 0) ? 1 : 0; + esp_cpu_reset(other_core_id); + esp_cpu_stall(other_core_id); +#endif + +#if SOC_WDT_SUPPORTED + // Disable TG0/TG1 watchdogs + wdt_hal_context_t wdt0_context = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0}; + wdt_hal_write_protect_disable(&wdt0_context); + wdt_hal_disable(&wdt0_context); + wdt_hal_write_protect_enable(&wdt0_context); + + wdt_hal_context_t wdt1_context = {.inst = WDT_MWDT1, .mwdt_dev = &TIMERG1}; + wdt_hal_write_protect_disable(&wdt1_context); + wdt_hal_disable(&wdt1_context); + wdt_hal_write_protect_enable(&wdt1_context); +#endif /* SOC_WDT_SUPPORTED */ + +#ifdef CONFIG_FREERTOS_TASK_CREATE_ALLOW_EXT_MEM + if (esp_ptr_external_ram(esp_cpu_get_sp())) { + // If stack is in external RAM (CONFIG_FREERTOS_TASK_CREATE_ALLOW_EXT_MEM), switch SP to + // internal RAM before disabling the cache to avoid a "Cache disabled but cached memory + // region accessed" crash. + uint32_t new_sp = ALIGN_DOWN((uint32_t)&_bss_end, 16); + rv_utils_set_sp((void *)new_sp); + } +#endif + + esp_restart_noos_inner(); +} diff --git a/components/esp_system/test_apps/esp_system_unity_tests/main/test_reset_reason.c b/components/esp_system/test_apps/esp_system_unity_tests/main/test_reset_reason.c index baaa1048ea7..ab7d73fb2aa 100644 --- a/components/esp_system/test_apps/esp_system_unity_tests/main/test_reset_reason.c +++ b/components/esp_system/test_apps/esp_system_unity_tests/main/test_reset_reason.c @@ -323,15 +323,31 @@ TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_BROWNOUT after brownout event", check_reset_reason_brownout); #ifdef CONFIG_FREERTOS_TASK_CREATE_ALLOW_EXT_MEM -#ifndef CONFIG_FREERTOS_UNICORE +#if (defined(CONFIG_IDF_TARGET_ARCH_XTENSA) && !defined(CONFIG_FREERTOS_UNICORE)) || defined(CONFIG_IDF_TARGET_ARCH_RISCV) +#include "esp_memory_utils.h" +#include "freertos/task.h" #if CONFIG_IDF_TARGET_ARCH_XTENSA #include "xt_instr_macros.h" #include "xtensa/config/xt_specreg.h" +#endif +/* IDF's xTaskCreateStatic[PinnedToCore]() takes the stack size in BYTES + * (not in words like upstream FreeRTOS). */ static int size_stack = 1024 * 4; static StackType_t *start_addr_stack; -static int fibonacci(int n, void* func(void)) +static void func_do_exception(void) +{ + *((volatile int *) 0x01) = 0; +} + +#if CONFIG_IDF_TARGET_ARCH_XTENSA +/* On Xtensa (windowed ABI), recursing forces the register window to wrap, + * which triggers overflow/underflow exceptions that spill/fill registers + * to/from the (SPIRAM-backed) task stack. This makes sure SP is genuinely + * pointing into SPIRAM and that spilled frames live there too when func() + * is finally called from deep inside the recursion. */ +static int fibonacci(int n, void *func(void)) { int tmp1 = n, tmp2 = n; uint32_t base, start; @@ -349,6 +365,7 @@ static int fibonacci(int n, void* func(void)) printf("fib = %d\n", (tmp1 - tmp2) + fib); return fib; } +#endif // CONFIG_IDF_TARGET_ARCH_XTENSA static void test_task(void *func) { @@ -358,30 +375,13 @@ static void test_task(void *func) } else { printf("restart_task: uses internal stack, addr_stack = %p\n", start_addr_stack); } +#if CONFIG_IDF_TARGET_ARCH_XTENSA fibonacci(35, func); -} - -static void func_do_exception(void) -{ - *((int *) 0) = 0; -} - -static void init_restart_task(void) -{ - StackType_t *stack_for_task = (StackType_t *) heap_caps_calloc(1, size_stack, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); - printf("init_task: current addr_stack = %p, stack_for_task = %p\n", esp_cpu_get_sp(), stack_for_task); - static StaticTask_t task_buf; - xTaskCreateStaticPinnedToCore(test_task, "test_task", size_stack, esp_restart, 5, stack_for_task, &task_buf, 1); - while (1) { }; -} - -static void init_task_do_exception(void) -{ - StackType_t *stack_for_task = (StackType_t *) heap_caps_calloc(1, size_stack, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); - printf("init_task: current addr_stack = %p, stack_for_task = %p\n", esp_cpu_get_sp(), stack_for_task); - static StaticTask_t task_buf; - xTaskCreateStaticPinnedToCore(test_task, "test_task", size_stack, func_do_exception, 5, stack_for_task, &task_buf, 1); - while (1) { }; +#else + /* RISC-V has no register windows, so no need to recurse. Just invoke + * the test function directly from this task (whose stack is in SPIRAM). */ + ((void (*)(void))func)(); +#endif } static void test1_finish(void) @@ -396,6 +396,38 @@ static void test2_finish(void) printf("test - OK\n"); } +#if CONFIG_IDF_TARGET_ARCH_XTENSA +#ifndef CONFIG_FREERTOS_UNICORE +#define CREATE_TEST_TASK(stack, buf, entry) \ + xTaskCreateStaticPinnedToCore(test_task, "test_task", size_stack, (entry), 5, (stack), (buf), 1) +#endif // !CONFIG_FREERTOS_UNICORE +#else // RISCV +#define CREATE_TEST_TASK(stack, buf, entry) \ + xTaskCreateStatic(test_task, "test_task", size_stack, (entry), 5, (stack), (buf)) +#endif + +#if defined(CREATE_TEST_TASK) + +static void init_restart_task(void) +{ + StackType_t *stack_for_task = (StackType_t *) heap_caps_calloc(1, size_stack, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); + TEST_ASSERT_NOT_NULL(stack_for_task); + printf("init_task: current addr_stack = %p, stack_for_task = %p\n", esp_cpu_get_sp(), stack_for_task); + static StaticTask_t task_buf; + CREATE_TEST_TASK(stack_for_task, &task_buf, esp_restart); + while (1) { } +} + +static void init_task_do_exception(void) +{ + StackType_t *stack_for_task = (StackType_t *) heap_caps_calloc(1, size_stack, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); + TEST_ASSERT_NOT_NULL(stack_for_task); + printf("init_task: current addr_stack = %p, stack_for_task = %p\n", esp_cpu_get_sp(), stack_for_task); + static StaticTask_t task_buf; + CREATE_TEST_TASK(stack_for_task, &task_buf, func_do_exception); + while (1) { } +} + TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_SW after restart in a task with spiram stack", "[spiram_stack]", init_restart_task, test1_finish); @@ -404,8 +436,8 @@ TEST_CASE_MULTIPLE_STAGES("reset reason ESP_RST_PANIC after an exception in a ta init_task_do_exception, test2_finish); -#endif //CONFIG_IDF_TARGET_ARCH_XTENSA -#endif // CONFIG_FREERTOS_UNICORE +#endif // CREATE_TEST_TASK +#endif // (XTENSA && !UNICORE) || RISCV #endif // CONFIG_FREERTOS_TASK_CREATE_ALLOW_EXT_MEM /* Not tested here: ESP_RST_SDIO */ diff --git a/components/riscv/include/riscv/rv_utils.h b/components/riscv/include/riscv/rv_utils.h index 7b9b6ddfbd6..44af2477d7e 100644 --- a/components/riscv/include/riscv/rv_utils.h +++ b/components/riscv/include/riscv/rv_utils.h @@ -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 */ @@ -106,6 +106,17 @@ FORCE_INLINE_ATTR void *rv_utils_get_sp(void) return sp; } +/* Switch the stack pointer to a new address. + * + * Unlike the Xtensa SET_STACK, no window register management is required on + * RISC-V; a plain register move is sufficient. The "memory" clobber prevents + * the compiler from reordering any accesses across the switch. + */ +FORCE_INLINE_ATTR void rv_utils_set_sp(void *new_sp) +{ + asm volatile ("mv sp, %0" :: "r"(new_sp) : "memory"); +} + FORCE_INLINE_ATTR uint32_t __attribute__((always_inline)) rv_utils_get_cycle_count(void) { #if !SOC_CPU_HAS_CSR_PC