Skip to content

Commit

Permalink
Merge branch 'feat/add-heap-walker-api' into 'master'
Browse files Browse the repository at this point in the history
feat(heap): Add walker to the heap component

Closes IDF-9189

See merge request espressif/esp-idf!29047
  • Loading branch information
SoucheSouche committed Mar 22, 2024
2 parents de2486b + 39f789d commit 573bd1b
Show file tree
Hide file tree
Showing 20 changed files with 436 additions and 26 deletions.
13 changes: 12 additions & 1 deletion components/esp_rom/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,16 @@ else()
endif()
endif()

if(CONFIG_HEAP_TLSF_USE_ROM_IMPL AND (CONFIG_ESP_ROM_TLSF_CHECK_PATCH OR CONFIG_HEAP_TLSF_CHECK_PATCH))
if(CONFIG_HEAP_TLSF_USE_ROM_IMPL AND CONFIG_ESP_ROM_TLSF_CHECK_PATCH)
# This file shall be included in the build if TLSF in ROM is activated
list(APPEND sources "patches/esp_rom_tlsf.c")
endif()

if(CONFIG_HEAP_TLSF_USE_ROM_IMPL AND CONFIG_ESP_ROM_MULTI_HEAP_WALK_PATCH)
# This file shall be included in the build if TLSF in ROM is activated
list(APPEND sources "patches/esp_rom_multi_heap.c")
endif()

list(APPEND private_required_comp soc hal)
endif()

Expand All @@ -64,6 +69,8 @@ if(CONFIG_HAL_WDT_USE_ROM_IMPL)
list(APPEND sources "patches/esp_rom_wdt.c")
endif()



if(CONFIG_ESP_ROM_HAS_FLASH_COUNT_PAGES_BUG OR CONFIG_ESP_ROM_HAS_CACHE_WRITEBACK_BUG)
list(APPEND sources "patches/esp_rom_cache_esp32s2_esp32s3.c")
endif()
Expand Down Expand Up @@ -216,6 +223,10 @@ else() # Regular app build
target_link_libraries(${COMPONENT_LIB} PRIVATE "-u tlsf_set_rom_patches")
endif()

if((CONFIG_ESP_ROM_TLSF_CHECK_PATCH OR CONFIG_ESP_ROM_MULTI_HEAP_WALK_PATCH))
target_link_libraries(${COMPONENT_LIB} PRIVATE "-u esp_rom_include_multi_heap_patch")
endif()

rom_linker_script("heap")
endif()

Expand Down
8 changes: 8 additions & 0 deletions components/esp_rom/esp32c2/Kconfig.soc_caps.in
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ config ESP_ROM_HAS_HEAP_TLSF
bool
default y

config ESP_ROM_TLSF_CHECK_PATCH
bool
default y

config ESP_ROM_MULTI_HEAP_WALK_PATCH
bool
default y

config ESP_ROM_HAS_LAYOUT_TABLE
bool
default y
Expand Down
2 changes: 2 additions & 0 deletions components/esp_rom/esp32c2/esp_rom_caps.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#define ESP_ROM_HAS_HAL_WDT (1) // ROM has the implementation of Watchdog HAL driver
#define ESP_ROM_HAS_HAL_SYSTIMER (1) // ROM has the implementation of Systimer HAL driver
#define ESP_ROM_HAS_HEAP_TLSF (1) // ROM has the implementation of the tlsf and multi-heap library
#define ESP_ROM_TLSF_CHECK_PATCH (1) // ROM does not contain the patch of tlsf_check_pool()
#define ESP_ROM_MULTI_HEAP_WALK_PATCH (1) // ROM does not contain the patch of multi_heap_walk()
#define ESP_ROM_HAS_LAYOUT_TABLE (1) // ROM has the layout table
#define ESP_ROM_HAS_SPI_FLASH (1) // ROM has the implementation of SPI Flash driver
#define ESP_ROM_HAS_NEWLIB (1) // ROM has newlib (at least parts of it) functions included
Expand Down
4 changes: 4 additions & 0 deletions components/esp_rom/esp32c5/beta3/esp32c5/Kconfig.soc_caps.in
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ config ESP_ROM_TLSF_CHECK_PATCH
bool
default y

config ESP_ROM_MULTI_HEAP_WALK_PATCH
bool
default y

config ESP_ROM_HAS_LAYOUT_TABLE
bool
default y
Expand Down
1 change: 1 addition & 0 deletions components/esp_rom/esp32c5/beta3/esp32c5/esp_rom_caps.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#define ESP_ROM_HAS_HAL_SYSTIMER (1) // ROM has the implementation of Systimer HAL driver
#define ESP_ROM_HAS_HEAP_TLSF (1) // ROM has the implementation of the tlsf and multi-heap library
#define ESP_ROM_TLSF_CHECK_PATCH (1) // ROM does not contain the patch of tlsf_check_pool()
#define ESP_ROM_MULTI_HEAP_WALK_PATCH (1) // ROM does not contain the patch of multi_heap_walk()
#define ESP_ROM_HAS_LAYOUT_TABLE (1) // ROM has the layout table
#define ESP_ROM_HAS_SPI_FLASH (1) // ROM has the implementation of SPI Flash driver
#define ESP_ROM_WITHOUT_REGI2C (1) // ROM has no regi2c APIs
Expand Down
4 changes: 4 additions & 0 deletions components/esp_rom/esp32c6/Kconfig.soc_caps.in
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ config ESP_ROM_TLSF_CHECK_PATCH
bool
default y

config ESP_ROM_MULTI_HEAP_WALK_PATCH
bool
default y

config ESP_ROM_HAS_LAYOUT_TABLE
bool
default y
Expand Down
1 change: 1 addition & 0 deletions components/esp_rom/esp32c6/esp_rom_caps.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#define ESP_ROM_HAS_HAL_SYSTIMER (1) // ROM has the implementation of Systimer HAL driver
#define ESP_ROM_HAS_HEAP_TLSF (1) // ROM has the implementation of the tlsf and multi-heap library
#define ESP_ROM_TLSF_CHECK_PATCH (1) // ROM does not contain the patch of tlsf_check_pool()
#define ESP_ROM_MULTI_HEAP_WALK_PATCH (1) // ROM does not contain the patch of multi_heap_walk()
#define ESP_ROM_HAS_LAYOUT_TABLE (1) // ROM has the layout table
#define ESP_ROM_HAS_SPI_FLASH (1) // ROM has the implementation of SPI Flash driver
#define ESP_ROM_HAS_REGI2C_BUG (1) // ROM has the regi2c bug
Expand Down
4 changes: 4 additions & 0 deletions components/esp_rom/esp32h2/Kconfig.soc_caps.in
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ config ESP_ROM_TLSF_CHECK_PATCH
bool
default y

config ESP_ROM_MULTI_HEAP_WALK_PATCH
bool
default y

config ESP_ROM_HAS_LAYOUT_TABLE
bool
default y
Expand Down
1 change: 1 addition & 0 deletions components/esp_rom/esp32h2/esp_rom_caps.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#define ESP_ROM_HAS_HAL_SYSTIMER (1) // ROM has the implementation of Systimer HAL driver
#define ESP_ROM_HAS_HEAP_TLSF (1) // ROM has the implementation of the tlsf and multi-heap library
#define ESP_ROM_TLSF_CHECK_PATCH (1) // ROM does not contain the patch of tlsf_check_pool()
#define ESP_ROM_MULTI_HEAP_WALK_PATCH (1) // ROM does not contain the patch of multi_heap_walk()
#define ESP_ROM_HAS_LAYOUT_TABLE (1) // ROM has the layout table
#define ESP_ROM_HAS_SPI_FLASH (1) // ROM has the implementation of SPI Flash driver
#define ESP_ROM_WITHOUT_REGI2C (1) // ROM has no regi2c APIs
Expand Down
43 changes: 43 additions & 0 deletions components/esp_rom/include/esp_rom_multi_heap.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>

#ifdef __cplusplus
extern "C" {
#endif

/** @brief Opaque handle to a registered heap */
typedef struct multi_heap_info *multi_heap_handle_t;

/**
* @brief Callback called when walking the given heap blocks of memory
*
* @param block_ptr Pointer to the block data
* @param block_size The size of the block
* @param block_used Block status. 0: free, 1: allocated
* @param user_data Opaque pointer to user defined data
*
* @return True if the walker is expected to continue the heap traversal
* False if the walker is expected to stop the traversal of the heap
*/
typedef bool (*multi_heap_walker_cb_t)(void *block_ptr, size_t block_size, int block_used, void *user_data);

/**
* @brief Call the tlsf_walk_pool function of the heap given as parameter with
* the walker function passed as parameter
*
* @param heap The heap to traverse
* @param walker_func The walker to trigger on each block of the heap
* @param user_data Opaque pointer to user defined data
*/
void multi_heap_walk(multi_heap_handle_t heap, multi_heap_walker_cb_t walker_func, void *user_data);

#ifdef __cplusplus
}
#endif
50 changes: 50 additions & 0 deletions components/esp_rom/patches/esp_rom_multi_heap.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

/*
* This file is a patch for the multi_heap.c file stored in ROM
* - added function multi_heap_walk
*/

#include <stddef.h>
#include <stdbool.h>
#include <string.h>

#include "esp_rom_multi_heap.h"

// Hook to force the linker to include this file
void esp_rom_include_multi_heap_patch(void)
{
}

/*!
* @brief Opaque types for TLSF implementation
*/
typedef void* tlsf_t;
typedef void* pool_t;
typedef void* tlsf_walker;

typedef struct multi_heap_info {
void *lock;
size_t free_bytes;
size_t minimum_free_bytes;
size_t pool_size;
void* heap_data;
} heap_t;

extern void tlsf_walk_pool(pool_t pool, tlsf_walker walker, void* user);
extern pool_t tlsf_get_pool(tlsf_t tlsf);
extern void multi_heap_internal_lock(multi_heap_handle_t heap);
extern void multi_heap_internal_unlock(multi_heap_handle_t heap);

void multi_heap_walk(multi_heap_handle_t heap, multi_heap_walker_cb_t walker_func, void *user_data)
{
assert(heap != NULL);

multi_heap_internal_lock(heap);
tlsf_walk_pool(tlsf_get_pool(heap->heap_data), walker_func, user_data);
multi_heap_internal_unlock(heap);
}
68 changes: 64 additions & 4 deletions components/esp_rom/patches/esp_rom_tlsf.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand All @@ -15,6 +15,7 @@
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>

#include "esp_rom_caps.h"
#include "esp_rom_tlsf.h"
Expand All @@ -24,13 +25,17 @@
*/
typedef void* tlsf_t;
typedef void* pool_t;
typedef void* tlsf_walker;
typedef ptrdiff_t tlsfptr_t;

/* ----------------------------------------------------------------
* Bring certain inline functions, macro and structures from the
* tlsf ROM implementation to be able to compile the patch.
* ---------------------------------------------------------------- */

#if !defined (tlsf_assert)
#define tlsf_assert assert
#endif

#define tlsf_cast(t, exp) ((t) (exp))

#define block_header_free_bit (1 << 0)
Expand Down Expand Up @@ -72,6 +77,30 @@ static inline __attribute__((always_inline)) block_header_t* block_from_ptr(cons
tlsf_cast(unsigned char*, ptr) - block_start_offset);
}

static inline __attribute__((always_inline)) block_header_t* offset_to_block(const void* ptr, size_t size)
{
return tlsf_cast(block_header_t*, tlsf_cast(tlsfptr_t, ptr) + size);
}

static inline __attribute__((always_inline)) int block_is_last(const block_header_t* block)
{
return block_size(block) == 0;
}

static inline __attribute__((always_inline)) void* block_to_ptr(const block_header_t* block)
{
return tlsf_cast(void*,
tlsf_cast(unsigned char*, block) + block_start_offset);
}

static inline __attribute__((always_inline)) block_header_t* block_next(const block_header_t* block)
{
block_header_t* next = offset_to_block(block_to_ptr(block),
block_size(block) - block_header_overhead);
tlsf_assert(!block_is_last(block));
return next;
}

/* ----------------------------------------------------------------
* End of the environment necessary to compile and link the patch
* defined below
Expand All @@ -92,7 +121,9 @@ typedef struct integrity_t
int status;
} integrity_t;

static void integrity_walker(void* ptr, size_t size, int used, void* user)
typedef bool (*tlsf_walker)(void* ptr, size_t size, int used, void* user);

static bool integrity_walker(void* ptr, size_t size, int used, void* user)
{
block_header_t* block = block_from_ptr(ptr);
integrity_t* integ = tlsf_cast(integrity_t*, user);
Expand Down Expand Up @@ -124,9 +155,38 @@ static void integrity_walker(void* ptr, size_t size, int used, void* user)

integ->prev_status = this_status;
integ->status += status;

return true;
}

static bool default_walker(void* ptr, size_t size, int used, void* user)
{
(void)user;
printf("\t%p %s size: %x (%p)\n", ptr, used ? "used" : "free", (unsigned int)size, block_from_ptr(ptr));
return true;
}

void tlsf_walk_pool(pool_t pool, tlsf_walker walker, void* user)
{
tlsf_walker pool_walker = walker ? walker : default_walker;
block_header_t* block =
offset_to_block(pool, -(int)block_header_overhead);

bool ret_val = true;
while (block && !block_is_last(block) && ret_val == true)
{
ret_val = pool_walker(
block_to_ptr(block),
block_size(block),
!block_is_free(block),
user);

if (ret_val == true) {
block = block_next(block);
}
}
}

extern void tlsf_walk_pool(pool_t pool, tlsf_walker walker, void* user);
int tlsf_check_pool(pool_t pool)
{
/* Check that the blocks are physically correct. */
Expand Down
9 changes: 0 additions & 9 deletions components/heap/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -119,15 +119,6 @@ menu "Heap memory debugging"
features will be added and bugs will be fixed in the IDF source
but cannot be synced to ROM.

config HEAP_TLSF_CHECK_PATCH
bool "Patch the tlsf_check_pool() for ROM HEAP TLSF implementation"
depends on HEAP_TLSF_USE_ROM_IMPL && IDF_TARGET_ESP32C2 && ESP32C2_REV_MIN_FULL < 200
default y
help
ROM does not contain the patch of tlsf_check_pool() allowing perform
the integrity checking on used blocks. The patch to allow such check
needs to be applied.

config HEAP_PLACE_FUNCTION_INTO_FLASH
bool "Force the entire heap component to be placed in flash memory"
depends on !HEAP_TLSF_USE_ROM_IMPL
Expand Down
Loading

0 comments on commit 573bd1b

Please sign in to comment.