From f404768fd147104c4dd9f5869633fb21c31b98cc Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 15 Apr 2026 13:48:11 -1000 Subject: [PATCH] =?UTF-8?q?libretiny:=20fix=20BK72xx=20build=20=E2=80=94?= =?UTF-8?q?=20guard=20portYIELD=5FFROM=5FISR;=20use=20.data.iram=5Ftext?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two issues surfaced building cb3s-test.yaml: 1. BK72xx's ARM9 FreeRTOS port does not define portYIELD_FROM_ISR; context switches happen naturally at IRQ exit. Wrap the call in #ifdef so the wake path compiles on ports that lack it. 2. Placing functions directly in section(".data") provoked assembler "ignoring changed section attributes" warnings and a hard DWARF error ("leb128 operand is an undefined symbol: .LVU31") because the compiler emits code-style attributes ("ax") that collide with .data's data-style attributes ("aw"). Use section(".data.iram_text") instead; the linker still folds it into the .data output via "*(.data.*)", so the bytes land in SRAM via the SDK's .data copy, but the assembler no longer sees conflicting attributes. --- esphome/components/libretiny/patch_linker.py.script | 7 ++++--- esphome/core/hal.h | 11 +++++++---- esphome/core/wake.h | 6 ++++++ 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/esphome/components/libretiny/patch_linker.py.script b/esphome/components/libretiny/patch_linker.py.script index 56a42db0ee0..b62ec1a5fb2 100644 --- a/esphome/components/libretiny/patch_linker.py.script +++ b/esphome/components/libretiny/patch_linker.py.script @@ -6,9 +6,10 @@ import re # BK72xx linker templates declare the SRAM region as "(rw!x)" — read/write but # not executable. That prevents the linker from emitting functions we mark -# IRAM_ATTR (defined as section(".data") on BK72xx in esphome/core/hal.h) into -# the .data output section, which is the only section the SDK startup code -# copies from flash into SRAM before main() runs. +# IRAM_ATTR (defined as section(".data.iram_text") on BK72xx in +# esphome/core/hal.h; folded into .data by the linker's "*(.data.*)" glob) +# into the .data output section, which is the only section the SDK startup +# code copies from flash into SRAM before main() runs. # # LibreTiny's own Wi-Fi driver already runs code from SRAM at runtime, so the # BK72xx MMU permits execution from that region; the "!x" is a stale hint in diff --git a/esphome/core/hal.h b/esphome/core/hal.h index 4009950ea04..aa36a1f03dd 100644 --- a/esphome/core/hal.h +++ b/esphome/core/hal.h @@ -28,15 +28,18 @@ // varies per family, based on what each linker script already supports: // - RTL8710B (AmebaZ): ".image2.ram.text" output section exists. // - RTL8720C (AmebaZ2): "*(.sram.text*)" is already consumed. -// - BK72xx / LN882H: stock linker script has no RAM text section, so we -// piggyback on ".data" — the SDK startup code copies .data from flash into -// SRAM before main() runs, so the function body ends up in executable RAM. +// - BK72xx / LN882H: the stock linker script has no RAM text section, so we +// use ".data.iram_text" which the linker's "*(.data.*)" glob folds into +// the .data output section. The SDK startup code copies .data from flash +// into SRAM before main() runs, so the function body ends up in executable +// RAM. Using ".data.*" instead of plain ".data" keeps the assembler happy +// (no section-attribute collision) while still landing in the right place. #if defined(USE_LIBRETINY_VARIANT_RTL8710B) #define IRAM_ATTR __attribute__((noinline, section(".image2.ram.text"))) #elif defined(USE_LIBRETINY_VARIANT_RTL8720C) #define IRAM_ATTR __attribute__((noinline, section(".sram.text"))) #else -#define IRAM_ATTR __attribute__((noinline, section(".data"))) +#define IRAM_ATTR __attribute__((noinline, section(".data.iram_text"))) #endif #define PROGMEM diff --git a/esphome/core/wake.h b/esphome/core/wake.h index f0a2d34b502..5733ee65f6c 100644 --- a/esphome/core/wake.h +++ b/esphome/core/wake.h @@ -34,7 +34,13 @@ __attribute__((always_inline)) inline void wake_main_task_any_context() { if (in_isr_context()) { BaseType_t px_higher_priority_task_woken = pdFALSE; esphome_main_task_notify_from_isr(&px_higher_priority_task_woken); +#ifdef portYIELD_FROM_ISR portYIELD_FROM_ISR(px_higher_priority_task_woken); +#else + // ARM9 FreeRTOS port (BK72xx) does not define portYIELD_FROM_ISR; the IRQ + // exit sequence performs the context switch if one was requested. + (void) px_higher_priority_task_woken; +#endif } else { esphome_main_task_notify(); }