From 9fc54d30e5773822794028ddfb1f3373f4bd04fe Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 15 Apr 2026 16:05:12 -1000 Subject: [PATCH] libretiny: use native section names for RTL8710B; patcher now LN882H-only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RTL8710B's stock linker already consumes *(.image2.ram.text*) into its .ram_image2.text output (> BD_RAM), so hal.h can place IRAM_ATTR functions directly into section(".image2.ram.text") without any linker patching. RTL8720C already worked this way with section(".sram.text"). The patcher is now only needed for LN882H, whose stock linker has no glob that catches ".sram.text" — we inject KEEP(*(.sram.text*)) into .flash_copysection (> RAM0 AT> FLASH). This removes the _RTL8710B_IMAGE2 regex, the RTL8710B entry from _PATCHERS_BY_VARIANT, and simplifies the header comments. --- esphome/components/libretiny/__init__.py | 14 +++---- .../libretiny/patch_linker.py.script | 37 +++++++------------ esphome/core/hal.h | 6 +++ 3 files changed, 24 insertions(+), 33 deletions(-) diff --git a/esphome/components/libretiny/__init__.py b/esphome/components/libretiny/__init__.py index 21b176d5f0..e9449662a7 100644 --- a/esphome/components/libretiny/__init__.py +++ b/esphome/components/libretiny/__init__.py @@ -467,15 +467,11 @@ async def component_to_code(config): # it for project source files only. GCC uses the last -O flag. build_src_flags += " -Os" cg.add_platformio_option("build_src_flags", build_src_flags) - # IRAM_ATTR on LibreTiny expands to section(".sram.text") on families - # where the ISR-during-flash race is real (see esphome/core/hal.h). This - # pre-link hook routes that section into each family's executable RAM: - # - LN882H: inject KEEP(*(.sram.text*)) into .flash_copysection. - # - RTL8710B: inject KEEP(*(.sram.text*)) into .ram_image2.text. - # - RTL8720C: no-op (stock linker already consumes *(.sram.text*)). - # BK72xx (all variants) is no-op: the Beken SDK wraps every flash write - # in GLOBAL_INT_DISABLE() so no ISR can fire during a flash stall; the - # race IRAM_ATTR guards against cannot occur. + # IRAM_ATTR routes ISR code into RAM-executable sections (see + # esphome/core/hal.h). Most families need no linker help; LN882H is the + # exception — its stock linker has no glob for ".sram.text", so this + # pre-link hook injects KEEP(*(.sram.text*)) into .flash_copysection. + # The script also prints a post-link summary on all non-BK72xx families. cg.add_platformio_option("extra_scripts", ["pre:patch_linker.py"]) # dummy version code cg.add_define("USE_ARDUINO_VERSION_CODE", cg.RawExpression("VERSION_CODE(0, 0, 0)")) diff --git a/esphome/components/libretiny/patch_linker.py.script b/esphome/components/libretiny/patch_linker.py.script index 45b04e8f96..cb1d960201 100644 --- a/esphome/components/libretiny/patch_linker.py.script +++ b/esphome/components/libretiny/patch_linker.py.script @@ -5,26 +5,19 @@ import os import re import subprocess -# ESPHome marks ISR code IRAM_ATTR, which on LibreTiny expands to -# section(".sram.text") (see esphome/core/hal.h). Each family's linker script -# needs that section routed into RAM-resident *executable* memory so the -# function is callable while flash is busy (XIP stall, OTA, logger flash -# write): +# ESPHome marks ISR code IRAM_ATTR, which on LibreTiny maps to a section +# that each family's linker routes into RAM-executable memory so the function +# is callable while flash is busy (see esphome/core/hal.h for the per-family +# section names). # -# - LN882H: stock linker has ".flash_copysection" which is flash-to-RAM0 -# copied at startup; inject "KEEP(*(.sram.text*))" there. -# - RTL8710B (AmebaZ): stock linker has ".ram_image2.text" output section -# (which already consumes *(.image2.ram.text*)) — inject -# "KEEP(*(.sram.text*))" into it as a second input glob. -# - RTL8720C (AmebaZ2): stock linker already consumes "*(.sram.text*)", -# no-op. Loaded directly from the framework package so we cannot inject -# our __esphome_sram_text_start/end markers either; the post-link summary -# falls back to reading known IRAM_ATTR symbol addresses instead. +# Most families need no linker patching: +# - RTL8710B: hal.h uses section(".image2.ram.text"); stock linker consumes it. +# - RTL8720C: hal.h uses section(".sram.text"); stock linker consumes it. +# - BK72xx: IRAM_ATTR is a no-op (SDK masks FIQ+IRQ around flash writes). # -# BK72xx (all variants) have no .ld patcher: the Beken SDK wraps every flash -# operation in GLOBAL_INT_DISABLE() which masks FIQ + IRQ at the CPU, so no -# ISR can fire during a flash stall and the race IRAM_ATTR guards against -# cannot occur. IRAM_ATTR is a no-op on BK72xx (see esphome/core/hal.h). +# LN882H is the only family that needs patching: its stock linker has no glob +# that catches ".sram.text", so we inject KEEP(*(.sram.text*)) into the +# ".flash_copysection" output (which is flash-to-RAM0 copied at startup). _MARKER = "/* esphome .sram.text */" @@ -37,11 +30,6 @@ _KEEP_LINE = ( + _MARKER + "\n" ) _LN_COPY = re.compile(r"(\.flash_copysection\s*:\s*\{\s*\n)") -# RTL8710B's output section is ".ram_image2.text"; its stock linker consumes -# "*(.image2.ram.text*)" as an input glob inside that output, but we need to -# add a second input glob "*(.sram.text*)" so the ESPHome-marked functions -# land in the same RAM-resident output. -_RTL8710B_IMAGE2 = re.compile(r"(\.ram_image2\.text\s*:\s*\{\s*\n)") def _detect(env): @@ -83,11 +71,12 @@ def _inject_keep(host_section): # Variants not listed here intentionally have no .ld patcher: +# - RTL8710B: hal.h uses section(".image2.ram.text") which the stock linker +# already routes into .ram_image2.text (> BD_RAM). # - RTL8720C: stock linker already consumes *(.sram.text*). # - BK72xx (all): SDK masks FIQ+IRQ around flash writes, IRAM_ATTR is no-op. _PATCHERS_BY_VARIANT = { "LN882H": (_inject_keep(_LN_COPY),), - "RTL8710B": (_inject_keep(_RTL8710B_IMAGE2),), } diff --git a/esphome/core/hal.h b/esphome/core/hal.h index d3bc97d9c3..a0e13ef3c7 100644 --- a/esphome/core/hal.h +++ b/esphome/core/hal.h @@ -39,7 +39,13 @@ // layer. #if defined(USE_BK72XX) #define IRAM_ATTR +#elif defined(USE_LIBRETINY_VARIANT_RTL8710B) +// Stock linker consumes *(.image2.ram.text*) into .ram_image2.text (> BD_RAM). +#define IRAM_ATTR __attribute__((noinline, section(".image2.ram.text"))) #else +// RTL8720C: stock linker consumes *(.sram.text*) into .ram.code_text. +// LN882H: patch_linker.py.script injects *(.sram.text*) into +// .flash_copysection (> RAM0 AT> FLASH). #define IRAM_ATTR __attribute__((noinline, section(".sram.text"))) #endif #define PROGMEM