fix(esp32): Fix access to MALLOC_CAP_IRAM_8BIT byte array in loop

The Xtensa load/store handler did not properly handle 8/16-bit
memory access to IRAM regions configured with MALLOC_CAP_IRAM_8BIT
(and CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY=y) from a loop
(LBEG/LEND/LCOUNT) context. This caused the loop to exit after
the first access, instead of continuing to iterate as intended.

Closes https://github.com/espressif/esp-idf/issues/14127
This commit is contained in:
Konstantin Kondrashov
2026-05-01 13:10:48 +03:00
parent d0feda6e14
commit 15540b39f7
4 changed files with 223 additions and 23 deletions
@@ -0,0 +1,53 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* Zero-overhead loop adjustment helpers for Xtensa assembly code.
*
* Used by exception handlers to emulate loop hardware when an exception
* occurs at LEND so execution resumes at LBEG with LCOUNT decremented.
*/
#ifndef XTENSA_ZOL_MACROS_H
#define XTENSA_ZOL_MACROS_H
#if __XTENSA__
#include "xtensa/config/core-isa.h"
#include "xtensa/config/xt_specreg.h"
/**
* Adjust loop counter and return address for exceptions at LEND.
*
* When an exception occurs on instruction at LEND address of a zero-overhead loop,
* we must decrement LCOUNT and set EPC back to LBEG so the loop continues
* iterating after the exception is handled. Otherwise, the loop exits prematurely.
*
* if (EPC == LEND && LCOUNT != 0) {
* LCOUNT--;
* EPC = LBEG;
* }
*
* param[in/out] epc_reg - register containing EPC, updated to LBEG if needed
* param[in/out] tmp_reg - temporary register for intermediate values
*
* Return: Use epc_reg to set corrected EPC value.
*/
.macro XT_ZOL_EPC_LCOUNT_RESTORE epc_reg tmp_reg
#if XCHAL_HAVE_LOOPS
rsr \tmp_reg, XT_REG_LEND
bne \epc_reg, \tmp_reg, 1f
rsr \tmp_reg, XT_REG_LCOUNT
beqz \tmp_reg, 1f
addi \tmp_reg, \tmp_reg, -1
wsr \tmp_reg, XT_REG_LCOUNT
rsr \epc_reg, XT_REG_LBEG
1:
#endif
.endm
#endif /* __XTENSA__ */
#endif /* XTENSA_ZOL_MACROS_H */