mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-03 03:31:41 +03:00
Merge branch 'fix/esp32_iram_as_8bit_access_from_isr1' into 'master'
fix(xtensa): Fix ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY mode for ISR1 Closes IDF-15285 See merge request espressif/esp-idf!45737
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -8,14 +8,35 @@
|
||||
Test for LoadStore exception handlers. This test performs unaligned load and store in 32bit aligned addresses
|
||||
*/
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if CONFIG_IDF_TARGET_ARCH_XTENSA && CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY
|
||||
|
||||
#include <esp_types.h>
|
||||
#include <stdio.h>
|
||||
#include <esp_heap_caps.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_random.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "xtensa_api.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include <string.h>
|
||||
#include "unity.h"
|
||||
|
||||
#if CONFIG_IDF_TARGET_ARCH_XTENSA && CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY
|
||||
#define SW_ISR_NUM_L1 7 // CPU interrupt number for internal SW0 (level 1)
|
||||
#define SW_ISR_NUM_L3 29 // CPU interrupt number for internal SW1 (level 3)
|
||||
|
||||
typedef struct {
|
||||
uint8_t b8;
|
||||
uint16_t b16;
|
||||
uint8_t b8_2;
|
||||
uint32_t b32;
|
||||
} iram_data_t;
|
||||
|
||||
static volatile iram_data_t *s_iram;
|
||||
static volatile int isr_hits;
|
||||
|
||||
TEST_CASE("LoadStore Exception handler", "[freertos]")
|
||||
{
|
||||
int32_t val0 = 0xDEADBEEF;
|
||||
@@ -125,4 +146,75 @@ TEST_CASE("LoadStore Exception handler", "[freertos]")
|
||||
TEST_ASSERT_TRUE(heap_caps_check_integrity_all(true));
|
||||
heap_caps_free(arr);
|
||||
}
|
||||
|
||||
static void IRAM_ATTR level_isr(void *arg)
|
||||
{
|
||||
const int cpu_intr_num = *(const int *)arg;
|
||||
|
||||
// Clear the SW interrupt source
|
||||
xt_set_intclear(1 << cpu_intr_num);
|
||||
|
||||
// Schedule another pending level interrupt while still inside this ISR
|
||||
// to keep dispatch_c_isr in the interrupt loop handling. The pending
|
||||
// interrupt will be handled after this ISR returns.
|
||||
if (isr_hits == 0) {
|
||||
xt_set_intset(1 << cpu_intr_num);
|
||||
}
|
||||
|
||||
// 8/16-bit accesses to s_iram will trigger LoadStore/Alignment exceptions which changes the EXCSAVE_1 value
|
||||
s_iram->b16++;
|
||||
s_iram->b8 = 0x5A;
|
||||
s_iram->b8_2 = 0xA5;
|
||||
|
||||
isr_hits++;
|
||||
}
|
||||
|
||||
static void run_sw_isr_level(int int_level)
|
||||
{
|
||||
memset((void *)s_iram, 0, sizeof(iram_data_t));
|
||||
isr_hits = 0;
|
||||
|
||||
intr_handle_t handle;
|
||||
int cpu_intr_num = (int_level == 1) ? SW_ISR_NUM_L1 : SW_ISR_NUM_L3;
|
||||
TEST_ASSERT_EQUAL(ESP_OK, esp_intr_alloc((int_level == 1) ? ETS_INTERNAL_SW0_INTR_SOURCE : ETS_INTERNAL_SW1_INTR_SOURCE,
|
||||
(int_level == 1) ? ESP_INTR_FLAG_LEVEL1 : ESP_INTR_FLAG_LEVEL3,
|
||||
level_isr,
|
||||
(void *)&cpu_intr_num,
|
||||
&handle));
|
||||
|
||||
// Trigger the first interrupt; ISR will queue one more while running
|
||||
xt_set_intset(1 << cpu_intr_num);
|
||||
|
||||
// Wait for the ISR to be invoked twice
|
||||
TickType_t start = xTaskGetTickCount();
|
||||
while (isr_hits < 2 && (xTaskGetTickCount() - start) < pdMS_TO_TICKS(500)) {
|
||||
vTaskDelay(1);
|
||||
}
|
||||
|
||||
TEST_ASSERT_EQUAL(2, isr_hits);
|
||||
TEST_ASSERT_EQUAL_HEX8(0x5A, s_iram->b8);
|
||||
TEST_ASSERT_EQUAL_HEX8(0xA5, s_iram->b8_2);
|
||||
TEST_ASSERT_EQUAL_UINT16(2, s_iram->b16);
|
||||
TEST_ASSERT_EQUAL_UINT32(0, s_iram->b32);
|
||||
|
||||
esp_intr_free(handle);
|
||||
}
|
||||
|
||||
TEST_CASE("LoadStore: 8/16-bit field access in IRAM from ISRs when pending interrupts are present", "[freertos]")
|
||||
{
|
||||
s_iram = heap_caps_calloc(1, sizeof(*s_iram), MALLOC_CAP_IRAM_8BIT);
|
||||
TEST_ASSERT_NOT_NULL(s_iram);
|
||||
|
||||
esp_rom_printf("Running test in level-1 ISR...\n");
|
||||
run_sw_isr_level(1);
|
||||
esp_rom_printf("test passed\n");
|
||||
|
||||
esp_rom_printf("Running test in level-3 ISR...\n");
|
||||
run_sw_isr_level(3);
|
||||
esp_rom_printf("test passed\n");
|
||||
|
||||
heap_caps_free((void *)s_iram);
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); // Wait for memory to be freed, to avoid affecting other tests.
|
||||
}
|
||||
|
||||
#endif // CONFIG_IDF_TARGET_ARCH_XTENSA && CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY
|
||||
|
||||
@@ -39,6 +39,8 @@ from pytest_embedded_idf.utils import idf_parametrize
|
||||
'esp32c3',
|
||||
(pytest.mark.flash_suspend,),
|
||||
),
|
||||
# IRAM as 8-bit accessible memory
|
||||
('iram_as_8bit_access_mem', 'esp32'),
|
||||
],
|
||||
indirect=['config', 'target'],
|
||||
)
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_FREERTOS_UNICORE=y
|
||||
CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY=y
|
||||
CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* SPDX-FileContributor: 2016-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileContributor: 2016-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*/
|
||||
/*
|
||||
* Copyright (c) 2015-2019 Cadence Design Systems, Inc.
|
||||
@@ -104,7 +104,6 @@
|
||||
#include "soc/soc.h"
|
||||
#include "xt_asm_utils.h"
|
||||
|
||||
|
||||
/*
|
||||
--------------------------------------------------------------------------------
|
||||
In order for backtracing to be able to trace from the pre-exception stack
|
||||
@@ -129,6 +128,21 @@
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(XT_DEBUG_BACKTRACE) && defined(CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY)
|
||||
/*
|
||||
* For CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY we cannot rely on EXCSAVE_1
|
||||
* because accessing unaligned IRAM memory from a level-1 ISR would cause
|
||||
* LoadStore/Alignment exceptions and will overwrite EXCSAVE_1 before we read
|
||||
* it for backtracing. Keep a copy of EXCSAVE_1 in RAM instead.
|
||||
*/
|
||||
.section .noinit,"aw",@nobits
|
||||
.align 4
|
||||
_xt_excsave1_sp:
|
||||
.word 0
|
||||
.section .text
|
||||
#endif /* XT_DEBUG_BACKTRACE CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY */
|
||||
|
||||
|
||||
/*
|
||||
--------------------------------------------------------------------------------
|
||||
Defines used to access _xtos_interrupt_table.
|
||||
@@ -229,7 +243,17 @@
|
||||
*/
|
||||
#ifdef XT_DEBUG_BACKTRACE
|
||||
#ifndef __XTENSA_CALL0_ABI__
|
||||
#ifdef CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY
|
||||
.if \level == 1
|
||||
/* For level 1, nested LoadStore/Alignment Exceptions may clobber EXCSAVE_1, this is why we use _xt_excsave1_sp. */
|
||||
movi a0, _xt_excsave1_sp
|
||||
l32i a0, a0, 0
|
||||
.else
|
||||
rsr a0, XT_REG_EXCSAVE_1 + \level - 1 /* EXCSAVE_x for this level */
|
||||
.endif
|
||||
#else
|
||||
rsr a0, XT_REG_EXCSAVE_1 + \level - 1 /* Get exception frame pointer stored in EXCSAVE_x */
|
||||
#endif /* CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY */
|
||||
l32i a3, a0, XT_STK_A0 /* Copy pre-exception a0 (return address) */
|
||||
s32e a3, a1, -16
|
||||
l32i a3, a0, XT_STK_A1 /* Copy pre-exception a1 (stack pointer) */
|
||||
@@ -1212,12 +1236,20 @@ _xt_lowint1:
|
||||
movi a0, _xt_user_exit /* save exit point for dispatch */
|
||||
s32i a0, sp, XT_STK_EXIT
|
||||
|
||||
/* EXCSAVE_1 should now be free to use. Use it to keep a copy of the
|
||||
current stack pointer that points to the exception frame (XT_STK_FRAME).*/
|
||||
#ifdef XT_DEBUG_BACKTRACE
|
||||
#ifndef __XTENSA_CALL0_ABI__
|
||||
#ifdef CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY
|
||||
/* EXCSAVE_1 can not be used to store a copy of the current stack pointer for debug backtrace,
|
||||
because it is used to store the return address for the load/store error handler.
|
||||
Use a fixed memory location (_xt_excsave1_sp) in RAM instead. */
|
||||
movi a0, _xt_excsave1_sp
|
||||
s32i sp, a0, 0 /* store frame pointer (SP) to RAM */
|
||||
#else
|
||||
/* EXCSAVE_1 should now be free to use. Use it to keep a copy of the
|
||||
current stack pointer that points to the exception frame (XT_STK_FRAME).*/
|
||||
mov a0, sp
|
||||
wsr a0, XT_REG_EXCSAVE_1
|
||||
#endif /* CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user