|
1 | 1 | /* |
2 | | - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD |
| 2 | + * SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD |
3 | 3 | * |
4 | 4 | * SPDX-License-Identifier: Apache-2.0 |
5 | 5 | */ |
|
14 | 14 | #include <string.h> |
15 | 15 | #include <assert.h> |
16 | 16 |
|
| 17 | +#include "sdkconfig.h" |
17 | 18 | #include "esp_rom_multi_heap.h" |
18 | 19 |
|
19 | 20 | // Hook to force the linker to include this file |
@@ -49,3 +50,101 @@ void multi_heap_walk(multi_heap_handle_t heap, multi_heap_walker_cb_t walker_fun |
49 | 50 | tlsf_walk_pool(tlsf_get_pool(heap->heap_data), walker_func, user_data); |
50 | 51 | multi_heap_internal_unlock(heap); |
51 | 52 | } |
| 53 | + |
| 54 | +/** |
| 55 | + * @brief Structure used in multi_heap_find_containing_block to retain |
| 56 | + * information while walking a given heap to find the allocated block |
| 57 | + * containing the pointer ptr. |
| 58 | + * |
| 59 | + * @note The block_ptr gets filled with the pointer to the allocated block |
| 60 | + * containing the ptr. |
| 61 | + */ |
| 62 | +typedef struct containing_block_data { |
| 63 | + void *ptr; ///< Pointer to find the containing block of |
| 64 | + void *block_ptr; ///< Pointer to the containing block |
| 65 | +} containing_block_data_t; |
| 66 | + |
| 67 | + |
| 68 | +#if CONFIG_HEAP_POISONING_DISABLED |
| 69 | + void *multi_heap_find_containing_block(multi_heap_handle_t heap, void *ptr) |
| 70 | + __attribute__((alias("multi_heap_find_containing_block_impl"))); |
| 71 | +#endif |
| 72 | + |
| 73 | +typedef struct block_header_t |
| 74 | +{ |
| 75 | + /* Points to the previous physical block. */ |
| 76 | + struct block_header_t* prev_phys_block; |
| 77 | + |
| 78 | + /* The size of this block, excluding the block header. */ |
| 79 | + size_t size; |
| 80 | + |
| 81 | + /* Next and previous free blocks. */ |
| 82 | + struct block_header_t* next_free; |
| 83 | + struct block_header_t* prev_free; |
| 84 | +} block_header_t; |
| 85 | + |
| 86 | +#define tlsf_cast(t, exp) ((t) (exp)) |
| 87 | +#define block_header_free_bit (1UL << 0) |
| 88 | +#define block_header_prev_free_bit (1UL << 1) |
| 89 | +#define block_header_overhead (sizeof(size_t)) |
| 90 | +#define block_start_offset (offsetof(block_header_t, size) + sizeof(size_t)) |
| 91 | + |
| 92 | +#if !defined (tlsf_assert) |
| 93 | +#define tlsf_assert assert |
| 94 | +#endif |
| 95 | + |
| 96 | +static inline __attribute__((always_inline)) void* block_to_ptr(const block_header_t* block) |
| 97 | +{ |
| 98 | + return tlsf_cast(void*, |
| 99 | + tlsf_cast(unsigned char*, block) + block_start_offset); |
| 100 | +} |
| 101 | +static size_t block_size(const block_header_t* block) |
| 102 | +{ |
| 103 | + return block->size & ~(block_header_free_bit | block_header_prev_free_bit); |
| 104 | +} |
| 105 | +static block_header_t* offset_to_block(const void* ptr, size_t size) |
| 106 | +{ |
| 107 | + return tlsf_cast(block_header_t*, tlsf_cast(ptrdiff_t, ptr) + size); |
| 108 | +} |
| 109 | +static int block_is_free(const block_header_t* block) |
| 110 | +{ |
| 111 | + return tlsf_cast(int, block->size & block_header_free_bit); |
| 112 | +} |
| 113 | +static int block_is_last(const block_header_t* block) |
| 114 | +{ |
| 115 | + return block_size(block) == 0; |
| 116 | +} |
| 117 | +static block_header_t* block_next(const block_header_t* block) |
| 118 | +{ |
| 119 | + block_header_t* next = offset_to_block(block_to_ptr(block), |
| 120 | + block_size(block) - block_header_overhead); |
| 121 | + tlsf_assert(!block_is_last(block)); |
| 122 | + return next; |
| 123 | +} |
| 124 | + |
| 125 | +void* tlsf_find_containing_block(pool_t pool, void *ptr) |
| 126 | +{ |
| 127 | + block_header_t* block = offset_to_block(pool, -(int)block_header_overhead); |
| 128 | + |
| 129 | + while (block && !block_is_last(block)) |
| 130 | + { |
| 131 | + if (!block_is_free(block)) { |
| 132 | + void *block_end = block_to_ptr(block) + block_size(block); |
| 133 | + if (block_to_ptr(block) <= ptr && block_end > ptr) { |
| 134 | + // we found the containing block, return |
| 135 | + return block_to_ptr(block); |
| 136 | + } |
| 137 | + } |
| 138 | + |
| 139 | + block = block_next(block); |
| 140 | + } |
| 141 | + |
| 142 | + return NULL; |
| 143 | +} |
| 144 | + |
| 145 | +void *multi_heap_find_containing_block_impl(multi_heap_handle_t heap, void *ptr) |
| 146 | +{ |
| 147 | + void *block_ptr = tlsf_find_containing_block(tlsf_get_pool(heap->heap_data), ptr); |
| 148 | + assert(block_ptr); |
| 149 | + return block_ptr; |
| 150 | +} |
0 commit comments