From 8f198ffb2ed9038e42fd389309dc7734fed1acae Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 22 May 2026 21:31:10 -0500 Subject: [PATCH] [esp32] Pin static loop task stack to internal DRAM The static loop task TCB and stack added in #15659 had no explicit section attribute, so under some sdkconfig combinations (notably CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY) the linker can place them in PSRAM. That is unsafe when CONFIG_SPIRAM_XIP_FROM_PSRAM is also enabled, because the running task's stack must stay reachable while the flash cache is disabled (asserted by esp_task_stack_is_sane_cache_disabled). DRAM_ATTR keeps both objects in internal DRAM regardless of those configs. --- esphome/components/esp32/core.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/esphome/components/esp32/core.cpp b/esphome/components/esp32/core.cpp index 5249f4a59e..1819fdbaad 100644 --- a/esphome/components/esp32/core.cpp +++ b/esphome/components/esp32/core.cpp @@ -3,6 +3,7 @@ #include "esphome/core/application.h" #include "esphome/core/defines.h" #include "preferences.h" +#include #include #include @@ -14,10 +15,14 @@ extern "C" __attribute__((weak)) void initArduino() {} namespace esphome { // HAL functions live in hal.cpp. This file keeps only the loop task setup. -TaskHandle_t loop_task_handle = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) -static StaticTask_t loop_task_tcb; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) -static StackType_t - loop_task_stack[ESPHOME_LOOP_TASK_STACK_SIZE]; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) +// Force the static TCB and stack into internal DRAM. Otherwise the linker may +// place them in PSRAM under configs like CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY, +// which is unsafe when CONFIG_SPIRAM_XIP_FROM_PSRAM is enabled because the running +// task's stack must be reachable while the flash cache is disabled. +TaskHandle_t loop_task_handle = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) +static StaticTask_t DRAM_ATTR loop_task_tcb{}; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) +static StackType_t DRAM_ATTR + loop_task_stack[ESPHOME_LOOP_TASK_STACK_SIZE]{}; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) void loop_task(void *pv_params) { setup();