From 388ed349e5746691b65ee9c6346db9ce7645c614 Mon Sep 17 00:00:00 2001 From: Guillaume Souchere Date: Thu, 7 Nov 2024 13:23:27 +0100 Subject: [PATCH] fix(heap): MALLOC_CAP_EXEC does not allocate in RTC IRAM This commit fixes the issue when trying to allocate memory with the MALLOC_CAP_EXEC in RTC memory. Prior to the fix, the heap allocator was returning an address in RTC DRAM. To fix this issue: - modified memory_layout.c of the concerned targets to fill the iram_address field in the rtc entry of the soc_memory_region array properly. - modified heap component related functions to return IRAM address when an allocation in RTC memory with MALLOC_CAP_EXEC is requested. Closes https://github.com/espressif/esp-idf/issues/14835 --- .../include/bootloader_memory_utils.h | 24 +++++++++++++++++-- .../esp_hw_support/include/esp_memory_utils.h | 24 +++++++++++++++++-- components/heap/heap_caps_base.c | 16 +++++++++---- components/heap/port/esp32s2/memory_layout.c | 8 +++---- 4 files changed, 59 insertions(+), 13 deletions(-) diff --git a/components/bootloader_support/include/bootloader_memory_utils.h b/components/bootloader_support/include/bootloader_memory_utils.h index adbf72a275..e77e4cc8aa 100644 --- a/components/bootloader_support/include/bootloader_memory_utils.h +++ b/components/bootloader_support/include/bootloader_memory_utils.h @@ -28,7 +28,12 @@ extern "C" { */ __attribute__((always_inline)) inline static bool esp_dram_match_iram(void) { - return (SOC_DRAM_LOW == SOC_IRAM_LOW && SOC_DRAM_HIGH == SOC_IRAM_HIGH); + bool dram_match_iram = (SOC_DRAM_LOW == SOC_IRAM_LOW) && + (SOC_DRAM_HIGH == SOC_IRAM_HIGH); +#if SOC_RTC_FAST_MEM_SUPPORTED + dram_match_iram &= (SOC_RTC_IRAM_LOW == SOC_RTC_DRAM_LOW); +#endif + return dram_match_iram; } /** @@ -97,7 +102,7 @@ inline static bool esp_ptr_in_diram_iram(const void *p) { */ __attribute__((always_inline)) inline static bool esp_ptr_in_rtc_iram_fast(const void *p) { -#if SOC_RTC_FAST_MEM_SUPPORTED +#if SOC_RTC_FAST_MEM_SUPPORTED && (SOC_RTC_IRAM_LOW != SOC_RTC_DRAM_LOW) return ((intptr_t)p >= SOC_RTC_IRAM_LOW && (intptr_t)p < SOC_RTC_IRAM_HIGH); #else return false; @@ -151,6 +156,21 @@ inline static void * esp_ptr_diram_dram_to_iram(const void *p) { #endif } +/* Convert a RTC DRAM pointer to equivalent word address in RTC IRAM + + - Address must be word aligned + - Address must pass esp_ptr_in_rtc_dram_fast() test, or result will be invalid pointer +*/ +__attribute__((always_inline)) +inline static void * esp_ptr_rtc_dram_to_iram(const void *p) { + intptr_t ptr = (intptr_t)p; +#if SOC_RTC_FAST_MEM_SUPPORTED && (SOC_RTC_IRAM_LOW != SOC_RTC_DRAM_LOW) + return (void *) ( SOC_RTC_IRAM_LOW + (ptr - SOC_RTC_DRAM_LOW) ); +#else + return (void *) ptr; +#endif +} + /* Convert a D/IRAM IRAM pointer to equivalent word address in DRAM - Address must be word aligned diff --git a/components/esp_hw_support/include/esp_memory_utils.h b/components/esp_hw_support/include/esp_memory_utils.h index d17d6f2696..de0cea32c4 100644 --- a/components/esp_hw_support/include/esp_memory_utils.h +++ b/components/esp_hw_support/include/esp_memory_utils.h @@ -27,7 +27,12 @@ extern "C" { */ __attribute__((always_inline)) inline static bool esp_dram_match_iram(void) { - return (SOC_DRAM_LOW == SOC_IRAM_LOW && SOC_DRAM_HIGH == SOC_IRAM_HIGH); + bool dram_match_iram = (SOC_DRAM_LOW == SOC_IRAM_LOW) && + (SOC_DRAM_HIGH == SOC_IRAM_HIGH); +#if SOC_RTC_FAST_MEM_SUPPORTED + dram_match_iram &= (SOC_RTC_IRAM_LOW == SOC_RTC_DRAM_LOW); +#endif + return dram_match_iram; } /** @@ -96,7 +101,7 @@ inline static bool esp_ptr_in_diram_iram(const void *p) { */ __attribute__((always_inline)) inline static bool esp_ptr_in_rtc_iram_fast(const void *p) { -#if SOC_RTC_FAST_MEM_SUPPORTED +#if SOC_RTC_FAST_MEM_SUPPORTED && (SOC_RTC_IRAM_LOW != SOC_RTC_DRAM_LOW) return ((intptr_t)p >= SOC_RTC_IRAM_LOW && (intptr_t)p < SOC_RTC_IRAM_HIGH); #else return false; @@ -150,6 +155,21 @@ inline static void * esp_ptr_diram_dram_to_iram(const void *p) { #endif } +/* Convert a RTC DRAM pointer to equivalent word address in RTC IRAM + + - Address must be word aligned + - Address must pass esp_ptr_in_rtc_dram_fast() test, or result will be invalid pointer +*/ +__attribute__((always_inline)) +inline static void * esp_ptr_rtc_dram_to_iram(const void *p) { + intptr_t ptr = (intptr_t)p; +#if SOC_RTC_FAST_MEM_SUPPORTED && (SOC_RTC_IRAM_LOW != SOC_RTC_DRAM_LOW) + return (void *) ( SOC_RTC_IRAM_LOW + (ptr - SOC_RTC_DRAM_LOW) ); +#else + return (void *) ptr; +#endif +} + /* Convert a D/IRAM IRAM pointer to equivalent word address in DRAM - Address must be word aligned diff --git a/components/heap/heap_caps_base.c b/components/heap/heap_caps_base.c index e894790700..b7da26f179 100644 --- a/components/heap/heap_caps_base.c +++ b/components/heap/heap_caps_base.c @@ -38,14 +38,19 @@ HEAP_IRAM_ATTR static void *dram_alloc_to_iram_addr(void *addr, size_t len) { uintptr_t dstart = (uintptr_t)addr; //First word uintptr_t dend __attribute__((unused)) = dstart + len - 4; //Last word - assert(esp_ptr_in_diram_dram((void *)dstart)); - assert(esp_ptr_in_diram_dram((void *)dend)); + assert(esp_ptr_in_diram_dram((void *)dstart) || esp_ptr_in_rtc_dram_fast((void *)dstart)); + assert(esp_ptr_in_diram_dram((void *)dend) || esp_ptr_in_rtc_dram_fast((void *)dend)); assert((dstart & 3) == 0); assert((dend & 3) == 0); #if SOC_DIRAM_INVERTED // We want the word before the result to hold the DRAM address uint32_t *iptr = esp_ptr_diram_dram_to_iram((void *)dend); #else - uint32_t *iptr = esp_ptr_diram_dram_to_iram((void *)dstart); + uint32_t *iptr = NULL; + if (esp_ptr_in_rtc_dram_fast((void *)dstart)) { + iptr = esp_ptr_rtc_dram_to_iram((void *)dstart); + } else { + iptr = esp_ptr_diram_dram_to_iram((void *)dstart); + } #endif *iptr = dstart; return iptr + 1; @@ -57,7 +62,7 @@ HEAP_IRAM_ATTR void heap_caps_free( void *ptr) return; } - if (esp_ptr_in_diram_iram(ptr)) { + if (esp_ptr_in_diram_iram(ptr) || esp_ptr_in_rtc_iram_fast(ptr)) { //Memory allocated here is actually allocated in the DRAM alias region and //cannot be de-allocated as usual. dram_alloc_to_iram_addr stores a pointer to //the equivalent DRAM address, though; free that. @@ -132,7 +137,8 @@ HEAP_IRAM_ATTR NOINLINE_ATTR void *heap_caps_aligned_alloc_base(size_t alignment //This heap can satisfy all the requested capabilities. See if we can grab some memory using it. // If MALLOC_CAP_EXEC is requested but the DRAM and IRAM are on the same addresses (like on esp32c6) // proceed as for a default allocation. - if ((caps & MALLOC_CAP_EXEC) && !esp_dram_match_iram() && esp_ptr_in_diram_dram((void *)heap->start)) { + if (((caps & MALLOC_CAP_EXEC) && !esp_dram_match_iram()) && + (esp_ptr_in_diram_dram((void *)heap->start) || esp_ptr_in_rtc_dram_fast((void *)heap->start))) { //This is special, insofar that what we're going to get back is a DRAM address. If so, //we need to 'invert' it (lowest address in DRAM == highest address in IRAM and vice-versa) and //add a pointer to the DRAM equivalent before the address we're going to return. diff --git a/components/heap/port/esp32s2/memory_layout.c b/components/heap/port/esp32s2/memory_layout.c index 813e494050..e64ebe80aa 100644 --- a/components/heap/port/esp32s2/memory_layout.c +++ b/components/heap/port/esp32s2/memory_layout.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2010-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2010-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -51,11 +51,11 @@ enum { /** * Defined the attributes and allocation priority of each memory on the chip, * The heap allocator will traverse all types of memory types in column High Priority Matching and match the specified caps at first, - * if no memory caps matched or the allocation is failed, it will go to columns Medium Priorty Matching and Low Priority Matching + * if no memory caps matched or the allocation is failed, it will go to columns Medium Priority Matching and Low Priority Matching * in turn to continue matching. */ const soc_memory_type_desc_t soc_memory_types[] = { - /* Mem Type Name | High Priority Matching | Medium Priorty Matching | Low Priority Matching */ + /* Mem Type Name | High Priority Matching | Medium Priority Matching | Low Priority Matching */ [SOC_MEMORY_TYPE_DIRAM] = { "RAM", { MALLOC_DIRAM_BASE_CAPS, 0, 0 }}, //TODO, in fact, part of them support EDMA, to be supported. [SOC_MEMORY_TYPE_SPIRAM] = { "SPIRAM", { MALLOC_CAP_SPIRAM, ESP32S2_MEM_COMMON_CAPS, 0 }}, @@ -113,7 +113,7 @@ const soc_memory_region_t soc_memory_regions[] = { { 0x3FFF8000, 0x4000, SOC_MEMORY_TYPE_DIRAM, 0x40068000, false}, //Block 20, can be used for MAC dump, can be used as trace memory { 0x3FFFC000, 0x4000, SOC_MEMORY_TYPE_DIRAM, 0x4006C000, true}, //Block 21, can be used for MAC dump, can be used as trace memory, used for startup stack #ifdef CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP - { SOC_RTC_DRAM_LOW, 0x2000, SOC_MEMORY_TYPE_RTCRAM, 0, false}, //RTC Fast Memory + { SOC_RTC_DRAM_LOW, 0x2000, SOC_MEMORY_TYPE_RTCRAM, SOC_RTC_IRAM_LOW, false}, //RTC Fast Memory #endif };