Merge branch 'feature/register_heaps_runtime' into 'master'
heap: Support adding new heap regions at runtime See merge request !1159
This commit is contained in:
commit
4809c70899
10 changed files with 355 additions and 68 deletions
|
@ -40,7 +40,7 @@
|
||||||
|
|
||||||
#include "tcpip_adapter.h"
|
#include "tcpip_adapter.h"
|
||||||
|
|
||||||
#include "esp_heap_caps.h"
|
#include "esp_heap_caps_init.h"
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
#include "esp_system.h"
|
#include "esp_system.h"
|
||||||
#include "esp_spi_flash.h"
|
#include "esp_spi_flash.h"
|
||||||
|
|
|
@ -94,8 +94,8 @@ IRAM_ATTR void *heap_caps_malloc( size_t size, uint32_t caps )
|
||||||
}
|
}
|
||||||
for (int prio = 0; prio < SOC_MEMORY_TYPE_NO_PRIOS; prio++) {
|
for (int prio = 0; prio < SOC_MEMORY_TYPE_NO_PRIOS; prio++) {
|
||||||
//Iterate over heaps and check capabilities at this priority
|
//Iterate over heaps and check capabilities at this priority
|
||||||
for (int heap_idx = 0; heap_idx < num_registered_heaps; heap_idx++) {
|
heap_t *heap;
|
||||||
heap_t *heap = ®istered_heaps[heap_idx];
|
SLIST_FOREACH(heap, ®istered_heaps, next) {
|
||||||
if (heap->heap == NULL) {
|
if (heap->heap == NULL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -142,8 +142,8 @@ IRAM_ATTR void *heap_caps_malloc( size_t size, uint32_t caps )
|
||||||
IRAM_ATTR static heap_t *find_containing_heap(void *ptr )
|
IRAM_ATTR static heap_t *find_containing_heap(void *ptr )
|
||||||
{
|
{
|
||||||
intptr_t p = (intptr_t)ptr;
|
intptr_t p = (intptr_t)ptr;
|
||||||
for (size_t i = 0; i < num_registered_heaps; i++) {
|
heap_t *heap;
|
||||||
heap_t *heap = ®istered_heaps[i];
|
SLIST_FOREACH(heap, ®istered_heaps, next) {
|
||||||
if (heap->heap != NULL && p >= heap->start && p < heap->end) {
|
if (heap->heap != NULL && p >= heap->start && p < heap->end) {
|
||||||
return heap;
|
return heap;
|
||||||
}
|
}
|
||||||
|
@ -216,8 +216,8 @@ IRAM_ATTR void *heap_caps_realloc( void *ptr, size_t size, int caps)
|
||||||
size_t heap_caps_get_free_size( uint32_t caps )
|
size_t heap_caps_get_free_size( uint32_t caps )
|
||||||
{
|
{
|
||||||
size_t ret = 0;
|
size_t ret = 0;
|
||||||
for (int i = 0; i < num_registered_heaps; i++) {
|
heap_t *heap;
|
||||||
heap_t *heap = ®istered_heaps[i];
|
SLIST_FOREACH(heap, ®istered_heaps, next) {
|
||||||
if (heap_caps_match(heap, caps)) {
|
if (heap_caps_match(heap, caps)) {
|
||||||
ret += multi_heap_free_size(heap->heap);
|
ret += multi_heap_free_size(heap->heap);
|
||||||
}
|
}
|
||||||
|
@ -228,8 +228,8 @@ size_t heap_caps_get_free_size( uint32_t caps )
|
||||||
size_t heap_caps_get_minimum_free_size( uint32_t caps )
|
size_t heap_caps_get_minimum_free_size( uint32_t caps )
|
||||||
{
|
{
|
||||||
size_t ret = 0;
|
size_t ret = 0;
|
||||||
for (int i = 0; i < num_registered_heaps; i++) {
|
heap_t *heap;
|
||||||
heap_t *heap = ®istered_heaps[i];
|
SLIST_FOREACH(heap, ®istered_heaps, next) {
|
||||||
if (heap_caps_match(heap, caps)) {
|
if (heap_caps_match(heap, caps)) {
|
||||||
ret += multi_heap_minimum_free_size(heap->heap);
|
ret += multi_heap_minimum_free_size(heap->heap);
|
||||||
}
|
}
|
||||||
|
@ -248,8 +248,8 @@ void heap_caps_get_info( multi_heap_info_t *info, uint32_t caps )
|
||||||
{
|
{
|
||||||
bzero(info, sizeof(multi_heap_info_t));
|
bzero(info, sizeof(multi_heap_info_t));
|
||||||
|
|
||||||
for (int i = 0; i < num_registered_heaps; i++) {
|
heap_t *heap;
|
||||||
heap_t *heap = ®istered_heaps[i];
|
SLIST_FOREACH(heap, ®istered_heaps, next) {
|
||||||
if (heap_caps_match(heap, caps)) {
|
if (heap_caps_match(heap, caps)) {
|
||||||
multi_heap_info_t hinfo;
|
multi_heap_info_t hinfo;
|
||||||
multi_heap_get_info(heap->heap, &hinfo);
|
multi_heap_get_info(heap->heap, &hinfo);
|
||||||
|
@ -270,8 +270,8 @@ void heap_caps_print_heap_info( uint32_t caps )
|
||||||
{
|
{
|
||||||
multi_heap_info_t info;
|
multi_heap_info_t info;
|
||||||
printf("Heap summary for capabilities 0x%08X:\n", caps);
|
printf("Heap summary for capabilities 0x%08X:\n", caps);
|
||||||
for (int i = 0; i < num_registered_heaps; i++) {
|
heap_t *heap;
|
||||||
heap_t *heap = ®istered_heaps[i];
|
SLIST_FOREACH(heap, ®istered_heaps, next) {
|
||||||
if (heap_caps_match(heap, caps)) {
|
if (heap_caps_match(heap, caps)) {
|
||||||
multi_heap_get_info(heap->heap, &info);
|
multi_heap_get_info(heap->heap, &info);
|
||||||
|
|
||||||
|
|
|
@ -14,15 +14,20 @@
|
||||||
#include "heap_private.h"
|
#include "heap_private.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <esp_log.h>
|
#include <sys/lock.h>
|
||||||
#include <multi_heap.h>
|
|
||||||
#include <esp_heap_caps.h>
|
#include "esp_log.h"
|
||||||
#include <soc/soc_memory_layout.h>
|
#include "multi_heap.h"
|
||||||
|
#include "esp_heap_caps_init.h"
|
||||||
|
#include "soc/soc_memory_layout.h"
|
||||||
|
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
|
||||||
static const char *TAG = "heap_init";
|
static const char *TAG = "heap_init";
|
||||||
|
|
||||||
heap_t *registered_heaps;
|
/* Linked-list of registered heaps */
|
||||||
size_t num_registered_heaps;
|
struct registered_heap_ll registered_heaps;
|
||||||
|
|
||||||
static void register_heap(heap_t *region)
|
static void register_heap(heap_t *region)
|
||||||
{
|
{
|
||||||
|
@ -34,10 +39,10 @@ static void register_heap(heap_t *region)
|
||||||
|
|
||||||
void heap_caps_enable_nonos_stack_heaps()
|
void heap_caps_enable_nonos_stack_heaps()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < num_registered_heaps; i++) {
|
heap_t *heap;
|
||||||
|
SLIST_FOREACH(heap, ®istered_heaps, next) {
|
||||||
// Assume any not-yet-registered heap is
|
// Assume any not-yet-registered heap is
|
||||||
// a nonos-stack heap
|
// a nonos-stack heap
|
||||||
heap_t *heap = ®istered_heaps[i];
|
|
||||||
if (heap->heap == NULL) {
|
if (heap->heap == NULL) {
|
||||||
register_heap(heap);
|
register_heap(heap);
|
||||||
if (heap->heap != NULL) {
|
if (heap->heap != NULL) {
|
||||||
|
@ -125,10 +130,10 @@ void heap_caps_init()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Count the heaps left after merging */
|
/* Count the heaps left after merging */
|
||||||
num_registered_heaps = 0;
|
size_t num_heaps = 0;
|
||||||
for (int i = 0; i < soc_memory_region_count; i++) {
|
for (int i = 0; i < soc_memory_region_count; i++) {
|
||||||
if (regions[i].type != -1) {
|
if (regions[i].type != -1) {
|
||||||
num_registered_heaps++;
|
num_heaps++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,7 +141,7 @@ void heap_caps_init()
|
||||||
|
|
||||||
Once we have a heap to copy it to, we will copy it to a heap buffer.
|
Once we have a heap to copy it to, we will copy it to a heap buffer.
|
||||||
*/
|
*/
|
||||||
heap_t temp_heaps[num_registered_heaps];
|
heap_t temp_heaps[num_heaps];
|
||||||
size_t heap_idx = 0;
|
size_t heap_idx = 0;
|
||||||
|
|
||||||
ESP_EARLY_LOGI(TAG, "Initializing. RAM available for dynamic allocation:");
|
ESP_EARLY_LOGI(TAG, "Initializing. RAM available for dynamic allocation:");
|
||||||
|
@ -148,47 +153,112 @@ void heap_caps_init()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
heap_idx++;
|
heap_idx++;
|
||||||
assert(heap_idx <= num_registered_heaps);
|
assert(heap_idx <= num_heaps);
|
||||||
|
|
||||||
heap->type = region->type;
|
memcpy(heap->caps, type->caps, sizeof(heap->caps));
|
||||||
heap->start = region->start;
|
heap->start = region->start;
|
||||||
heap->end = region->start + region->size;
|
heap->end = region->start + region->size;
|
||||||
memcpy(heap->caps, type->caps, sizeof(heap->caps));
|
|
||||||
vPortCPUInitializeMutex(&heap->heap_mux);
|
vPortCPUInitializeMutex(&heap->heap_mux);
|
||||||
|
|
||||||
ESP_EARLY_LOGI(TAG, "At %08X len %08X (%d KiB): %s",
|
|
||||||
region->start, region->size, region->size / 1024, type->name);
|
|
||||||
|
|
||||||
if (type->startup_stack) {
|
if (type->startup_stack) {
|
||||||
/* Will be registered when OS scheduler starts */
|
/* Will be registered when OS scheduler starts */
|
||||||
heap->heap = NULL;
|
heap->heap = NULL;
|
||||||
} else {
|
} else {
|
||||||
register_heap(heap);
|
register_heap(heap);
|
||||||
}
|
}
|
||||||
|
SLIST_NEXT(heap, next) = NULL;
|
||||||
|
|
||||||
|
ESP_EARLY_LOGI(TAG, "At %08X len %08X (%d KiB): %s",
|
||||||
|
region->start, region->size, region->size / 1024, type->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(heap_idx == num_registered_heaps);
|
assert(heap_idx == num_heaps);
|
||||||
|
|
||||||
/* Allocate the permanent heap data that we'll use for runtime */
|
/* Allocate the permanent heap data that we'll use as a linked list at runtime.
|
||||||
registered_heaps = NULL;
|
|
||||||
for (int i = 0; i < num_registered_heaps; i++) {
|
Allocate this part of data contiguously, even though it's a linked list... */
|
||||||
|
assert(SLIST_EMPTY(®istered_heaps));
|
||||||
|
|
||||||
|
heap_t *heaps_array = NULL;
|
||||||
|
for (int i = 0; i < num_heaps; i++) {
|
||||||
if (heap_caps_match(&temp_heaps[i], MALLOC_CAP_8BIT)) {
|
if (heap_caps_match(&temp_heaps[i], MALLOC_CAP_8BIT)) {
|
||||||
/* use the first DRAM heap which can fit the data */
|
/* use the first DRAM heap which can fit the data */
|
||||||
registered_heaps = multi_heap_malloc(temp_heaps[i].heap, sizeof(heap_t) * num_registered_heaps);
|
heaps_array = multi_heap_malloc(temp_heaps[i].heap, sizeof(heap_t) * num_heaps);
|
||||||
if (registered_heaps != NULL) {
|
if (heaps_array != NULL) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(registered_heaps != NULL); /* if NULL, there's not enough free startup heap space */
|
assert(heaps_array != NULL); /* if NULL, there's not enough free startup heap space */
|
||||||
|
|
||||||
memcpy(registered_heaps, temp_heaps, sizeof(heap_t)*num_registered_heaps);
|
memcpy(heaps_array, temp_heaps, sizeof(heap_t)*num_heaps);
|
||||||
|
|
||||||
/* Now the heap_mux fields live on the heap, assign them */
|
/* Iterate the heaps and set their locks, also add them to the linked list. */
|
||||||
for (int i = 0; i < num_registered_heaps; i++) {
|
for (int i = 0; i < num_heaps; i++) {
|
||||||
if (registered_heaps[i].heap != NULL) {
|
if (heaps_array[i].heap != NULL) {
|
||||||
multi_heap_set_lock(registered_heaps[i].heap, ®istered_heaps[i].heap_mux);
|
multi_heap_set_lock(heaps_array[i].heap, &heaps_array[i].heap_mux);
|
||||||
|
}
|
||||||
|
if (i == 0) {
|
||||||
|
SLIST_INSERT_HEAD(®istered_heaps, &heaps_array[0], next);
|
||||||
|
} else {
|
||||||
|
SLIST_INSERT_AFTER(&heaps_array[i-1], &heaps_array[i], next);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
esp_err_t heap_caps_add_region(intptr_t start, intptr_t end)
|
||||||
|
{
|
||||||
|
if (start == 0) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < soc_memory_region_count; i++) {
|
||||||
|
const soc_memory_region_t *region = &soc_memory_regions[i];
|
||||||
|
if (region->start <= start && (region->start + region->size) > end) {
|
||||||
|
const uint32_t *caps = soc_memory_types[region->type].caps;
|
||||||
|
return heap_caps_add_region_with_caps(caps, start, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_ERR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t heap_caps_add_region_with_caps(const uint32_t caps[], intptr_t start, intptr_t end)
|
||||||
|
{
|
||||||
|
esp_err_t err = ESP_FAIL;
|
||||||
|
if (caps == NULL || start == 0 || end == 0 || end < start) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
heap_t *p_new = malloc(sizeof(heap_t));
|
||||||
|
if (p_new == NULL) {
|
||||||
|
err = ESP_ERR_NO_MEM;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
memcpy(p_new->caps, caps, sizeof(p_new->caps));
|
||||||
|
p_new->start = start;
|
||||||
|
p_new->end = end;
|
||||||
|
vPortCPUInitializeMutex(&p_new->heap_mux);
|
||||||
|
p_new->heap = multi_heap_register((void *)start, end - start);
|
||||||
|
SLIST_NEXT(p_new, next) = NULL;
|
||||||
|
if (p_new->heap == NULL) {
|
||||||
|
err = ESP_FAIL;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
multi_heap_set_lock(p_new->heap, &p_new->heap_mux);
|
||||||
|
|
||||||
|
/* (This insertion is atomic to registered_heaps, so
|
||||||
|
we don't need to worry about thread safety for readers,
|
||||||
|
only for writers. */
|
||||||
|
static _lock_t registered_heaps_write_lock;
|
||||||
|
_lock_acquire(®istered_heaps_write_lock);
|
||||||
|
SLIST_INSERT_HEAD(®istered_heaps, p_new, next);
|
||||||
|
_lock_release(®istered_heaps_write_lock);
|
||||||
|
|
||||||
|
err = ESP_OK;
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
free(p_new);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
|
@ -18,23 +18,36 @@
|
||||||
#include <freertos/FreeRTOS.h>
|
#include <freertos/FreeRTOS.h>
|
||||||
#include <soc/soc_memory_layout.h>
|
#include <soc/soc_memory_layout.h>
|
||||||
#include "multi_heap.h"
|
#include "multi_heap.h"
|
||||||
|
#include "rom/queue.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Some common heap registration data structures used
|
/* Some common heap registration data structures used
|
||||||
for heap_caps_init.c to share heap information with heap_caps.c
|
for heap_caps_init.c to share heap information with heap_caps.c
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Type for describing each registered heap */
|
/* Type for describing each registered heap */
|
||||||
typedef struct {
|
typedef struct heap_t_ {
|
||||||
size_t type;
|
|
||||||
uint32_t caps[SOC_MEMORY_TYPE_NO_PRIOS]; ///< Capabilities for the type of memory in this heap (as a prioritised set). Copied from soc_memory_types so it's in RAM not flash.
|
uint32_t caps[SOC_MEMORY_TYPE_NO_PRIOS]; ///< Capabilities for the type of memory in this heap (as a prioritised set). Copied from soc_memory_types so it's in RAM not flash.
|
||||||
intptr_t start;
|
intptr_t start;
|
||||||
intptr_t end;
|
intptr_t end;
|
||||||
portMUX_TYPE heap_mux;
|
portMUX_TYPE heap_mux;
|
||||||
multi_heap_handle_t heap;
|
multi_heap_handle_t heap;
|
||||||
|
SLIST_ENTRY(heap_t_) next;
|
||||||
} heap_t;
|
} heap_t;
|
||||||
|
|
||||||
extern heap_t *registered_heaps;
|
/* All registered heaps.
|
||||||
extern size_t num_registered_heaps;
|
|
||||||
|
Forms a single linked list, even though most entries are contiguous.
|
||||||
|
This means at the expense of 4 bytes per heap, new heaps can be
|
||||||
|
added at runtime in a fast & thread-safe way.
|
||||||
|
*/
|
||||||
|
extern SLIST_HEAD(registered_heap_ll, heap_t_) registered_heaps;
|
||||||
|
|
||||||
bool heap_caps_match(const heap_t *heap, uint32_t caps);
|
bool heap_caps_match(const heap_t *heap, uint32_t caps);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -33,25 +33,6 @@
|
||||||
#define MALLOC_CAP_SPISRAM (1<<10) ///< Memory must be in SPI SRAM
|
#define MALLOC_CAP_SPISRAM (1<<10) ///< Memory must be in SPI SRAM
|
||||||
#define MALLOC_CAP_INVALID (1<<31) ///< Memory can't be used / list end marker
|
#define MALLOC_CAP_INVALID (1<<31) ///< Memory can't be used / list end marker
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Initialize the capability-aware heap allocator.
|
|
||||||
*
|
|
||||||
* This is called once in the IDF startup code. Do not call it
|
|
||||||
* at other times.
|
|
||||||
*/
|
|
||||||
void heap_caps_init();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Enable heap(s) in memory regions where the startup stacks are located.
|
|
||||||
*
|
|
||||||
* On startup, the pro/app CPUs have a certain memory region they use as stack, so we
|
|
||||||
* cannot do allocations in the regions these stack frames are. When FreeRTOS is
|
|
||||||
* completely started, they do not use that memory anymore and heap(s) there can
|
|
||||||
* be enabled.
|
|
||||||
*/
|
|
||||||
void heap_caps_enable_nonos_stack_heaps();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Allocate a chunk of memory which has the given capabilities
|
* @brief Allocate a chunk of memory which has the given capabilities
|
||||||
*
|
*
|
||||||
|
|
83
components/heap/include/esp_heap_caps_init.h
Normal file
83
components/heap/include/esp_heap_caps_init.h
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
// Copyright 2017 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include "esp_heap_caps.h"
|
||||||
|
#include "soc/soc_memory_layout.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize the capability-aware heap allocator.
|
||||||
|
*
|
||||||
|
* This is called once in the IDF startup code. Do not call it
|
||||||
|
* at other times.
|
||||||
|
*/
|
||||||
|
void heap_caps_init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enable heap(s) in memory regions where the startup stacks are located.
|
||||||
|
*
|
||||||
|
* On startup, the pro/app CPUs have a certain memory region they use as stack, so we
|
||||||
|
* cannot do allocations in the regions these stack frames are. When FreeRTOS is
|
||||||
|
* completely started, they do not use that memory anymore and heap(s) there can
|
||||||
|
* be enabled.
|
||||||
|
*/
|
||||||
|
void heap_caps_enable_nonos_stack_heaps();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add a region of memory to the collection of heaps at runtime.
|
||||||
|
*
|
||||||
|
* Most memory regions are defined in soc_memory_layout.c for the SoC,
|
||||||
|
* and are registered via heap_caps_init(). Some regions can't be used
|
||||||
|
* immediately and are later enabled via heap_caps_enable_nonos_stack_heaps().
|
||||||
|
*
|
||||||
|
* Call this function to add a region of memory to the heap at some later time.
|
||||||
|
*
|
||||||
|
* This function does not consider any of the "reserved" regions or other data in soc_memory_layout, caller needs to
|
||||||
|
* consider this themselves.
|
||||||
|
*
|
||||||
|
* All memory within the region specified by start & end parameters must be otherwise unused.
|
||||||
|
*
|
||||||
|
* The capabilities of the newly registered memory will be determined by the start address, as looked up in the regions
|
||||||
|
* specified in soc_memory_layout.c.
|
||||||
|
*
|
||||||
|
* Use heap_caps_add_region_with_caps() to register a region with custom capabilities.
|
||||||
|
*
|
||||||
|
* @param start Start address of new region.
|
||||||
|
* @param end End address of new region.
|
||||||
|
*
|
||||||
|
* @return ESP_OK on success, ESP_ERR_INVALID_ARG if a parameter is invalid, ESP_ERR_NOT_FOUND if the
|
||||||
|
* specified start address doesn't reside in a known region, or any error returned by heap_caps_add_region_with_caps().
|
||||||
|
*/
|
||||||
|
esp_err_t heap_caps_add_region(intptr_t start, intptr_t end);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add a region of memory to the collection of heaps at runtime, with custom capabilities.
|
||||||
|
*
|
||||||
|
* Similar to heap_caps_add_region(), only custom memory capabilities are specified by the caller.
|
||||||
|
*
|
||||||
|
* @param caps Ordered array of capability masks for the new region, in order of priority. Must have length
|
||||||
|
* SOC_MEMORY_TYPE_NO_PRIOS. Does not need to remain valid after the call returns.
|
||||||
|
* @param start Start address of new region.
|
||||||
|
* @param end End address of new region.
|
||||||
|
*
|
||||||
|
* @return ESP_OK on success, ESP_ERR_INVALID_ARG if a parameter is invalid, ESP_ERR_NO_MEM if no
|
||||||
|
* memory to register new heap.
|
||||||
|
*/
|
||||||
|
esp_err_t heap_caps_add_region_with_caps(const uint32_t caps[], intptr_t start, intptr_t end);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
47
components/heap/test/test_runtime_heap_reg.c
Normal file
47
components/heap/test/test_runtime_heap_reg.c
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
Tests for registering new heap memory at runtime
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "unity.h"
|
||||||
|
#include "esp_heap_caps_init.h"
|
||||||
|
#include "esp_system.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
|
||||||
|
/* NOTE: This is not a well-formed unit test, it leaks memory */
|
||||||
|
TEST_CASE("Allocate new heap at runtime", "[heap][ignore]")
|
||||||
|
{
|
||||||
|
const size_t BUF_SZ = 1000;
|
||||||
|
const size_t HEAP_OVERHEAD_MAX = 200;
|
||||||
|
void *buffer = malloc(BUF_SZ);
|
||||||
|
TEST_ASSERT_NOT_NULL(buffer);
|
||||||
|
uint32_t before_free = esp_get_free_heap_size();
|
||||||
|
TEST_ESP_OK( heap_caps_add_region((intptr_t)buffer, (intptr_t)buffer + BUF_SZ) );
|
||||||
|
uint32_t after_free = esp_get_free_heap_size();
|
||||||
|
printf("Before %u after %u\n", before_free, after_free);
|
||||||
|
/* allow for some 'heap overhead' from accounting structures */
|
||||||
|
TEST_ASSERT(after_free > before_free + BUF_SZ - HEAP_OVERHEAD_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NOTE: This is not a well-formed unit test, it leaks memory and
|
||||||
|
may fail if run twice in a row without a reset.
|
||||||
|
*/
|
||||||
|
TEST_CASE("Allocate new heap with new capability", "[heap][ignore]")
|
||||||
|
{
|
||||||
|
const size_t BUF_SZ = 100;
|
||||||
|
const size_t ALLOC_SZ = 64; // More than half of BUF_SZ
|
||||||
|
const uint32_t MALLOC_CAP_INVENTED = (1<<30); /* this must be unused in esp_heap_caps.h */
|
||||||
|
|
||||||
|
/* no memory exists to provide this capability */
|
||||||
|
TEST_ASSERT_NULL( heap_caps_malloc(ALLOC_SZ, MALLOC_CAP_INVENTED) );
|
||||||
|
|
||||||
|
void *buffer = malloc(BUF_SZ);
|
||||||
|
TEST_ASSERT_NOT_NULL(buffer);
|
||||||
|
uint32_t caps[SOC_MEMORY_TYPE_NO_PRIOS] = { MALLOC_CAP_INVENTED };
|
||||||
|
TEST_ESP_OK( heap_caps_add_region_with_caps(caps, (intptr_t)buffer, (intptr_t)buffer + BUF_SZ) );
|
||||||
|
|
||||||
|
/* ta-da, it's now possible! */
|
||||||
|
TEST_ASSERT_NOT_NULL( heap_caps_malloc(ALLOC_SZ, MALLOC_CAP_INVENTED) );
|
||||||
|
}
|
||||||
|
|
|
@ -109,6 +109,7 @@ INPUT = \
|
||||||
##
|
##
|
||||||
## Memory Allocation #
|
## Memory Allocation #
|
||||||
../components/heap/include/esp_heap_caps.h \
|
../components/heap/include/esp_heap_caps.h \
|
||||||
|
../components/heap/include/esp_heap_caps_init.h \
|
||||||
../components/heap/include/multi_heap.h \
|
../components/heap/include/multi_heap.h \
|
||||||
## Interrupt Allocation
|
## Interrupt Allocation
|
||||||
../components/esp32/include/esp_intr_alloc.h \
|
../components/esp32/include/esp_intr_alloc.h \
|
||||||
|
|
|
@ -31,7 +31,13 @@ API Reference - Heap Allocation
|
||||||
|
|
||||||
.. include:: /_build/inc/esp_heap_caps.inc
|
.. include:: /_build/inc/esp_heap_caps.inc
|
||||||
|
|
||||||
|
API Reference - Initialisation
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
.. include:: /_build/inc/esp_heap_caps_init.inc
|
||||||
|
|
||||||
API Reference - Heap Regions
|
API Reference - Heap Regions
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
.. include:: /_build/inc/multi_heap.inc
|
.. include:: /_build/inc/multi_heap.inc
|
||||||
|
|
||||||
|
|
|
@ -134,7 +134,13 @@ CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32
|
||||||
CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2048
|
CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2048
|
||||||
CONFIG_MAIN_TASK_STACK_SIZE=4096
|
CONFIG_MAIN_TASK_STACK_SIZE=4096
|
||||||
CONFIG_IPC_TASK_STACK_SIZE=1024
|
CONFIG_IPC_TASK_STACK_SIZE=1024
|
||||||
CONFIG_NEWLIB_STDOUT_ADDCR=y
|
CONFIG_TIMER_TASK_STACK_SIZE=4096
|
||||||
|
CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF=y
|
||||||
|
# CONFIG_NEWLIB_STDOUT_LINE_ENDING_LF is not set
|
||||||
|
# CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR is not set
|
||||||
|
# CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF is not set
|
||||||
|
# CONFIG_NEWLIB_STDIN_LINE_ENDING_LF is not set
|
||||||
|
CONFIG_NEWLIB_STDIN_LINE_ENDING_CR=y
|
||||||
# CONFIG_NEWLIB_NANO_FORMAT is not set
|
# CONFIG_NEWLIB_NANO_FORMAT is not set
|
||||||
CONFIG_CONSOLE_UART_DEFAULT=y
|
CONFIG_CONSOLE_UART_DEFAULT=y
|
||||||
# CONFIG_CONSOLE_UART_CUSTOM is not set
|
# CONFIG_CONSOLE_UART_CUSTOM is not set
|
||||||
|
@ -174,6 +180,7 @@ CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY=2000
|
||||||
# CONFIG_ESP32_XTAL_FREQ_26 is not set
|
# CONFIG_ESP32_XTAL_FREQ_26 is not set
|
||||||
CONFIG_ESP32_XTAL_FREQ_AUTO=y
|
CONFIG_ESP32_XTAL_FREQ_AUTO=y
|
||||||
CONFIG_ESP32_XTAL_FREQ=0
|
CONFIG_ESP32_XTAL_FREQ=0
|
||||||
|
# CONFIG_DISABLE_BASIC_ROM_CONSOLE is not set
|
||||||
# CONFIG_NO_BLOBS is not set
|
# CONFIG_NO_BLOBS is not set
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -191,13 +198,21 @@ CONFIG_ESP32_WIFI_RX_BA_WIN=6
|
||||||
CONFIG_ESP32_WIFI_NVS_ENABLED=y
|
CONFIG_ESP32_WIFI_NVS_ENABLED=y
|
||||||
|
|
||||||
#
|
#
|
||||||
# PHY
|
# Phy
|
||||||
#
|
#
|
||||||
CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y
|
CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y
|
||||||
# CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION is not set
|
# CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION is not set
|
||||||
CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20
|
CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20
|
||||||
CONFIG_ESP32_PHY_MAX_TX_POWER=20
|
CONFIG_ESP32_PHY_MAX_TX_POWER=20
|
||||||
|
|
||||||
|
#
|
||||||
|
# Ethernet
|
||||||
|
#
|
||||||
|
CONFIG_DMA_RX_BUF_NUM=10
|
||||||
|
CONFIG_DMA_TX_BUF_NUM=10
|
||||||
|
# CONFIG_EMAC_L2_TO_L3_RX_BUF_MODE is not set
|
||||||
|
CONFIG_EMAC_TASK_PRIORITY=20
|
||||||
|
|
||||||
#
|
#
|
||||||
# FAT Filesystem support
|
# FAT Filesystem support
|
||||||
#
|
#
|
||||||
|
@ -317,6 +332,72 @@ CONFIG_MBEDTLS_MPI_USE_INTERRUPT=y
|
||||||
CONFIG_MBEDTLS_HARDWARE_SHA=y
|
CONFIG_MBEDTLS_HARDWARE_SHA=y
|
||||||
CONFIG_MBEDTLS_HAVE_TIME=y
|
CONFIG_MBEDTLS_HAVE_TIME=y
|
||||||
# CONFIG_MBEDTLS_HAVE_TIME_DATE is not set
|
# CONFIG_MBEDTLS_HAVE_TIME_DATE is not set
|
||||||
|
CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y
|
||||||
|
# CONFIG_MBEDTLS_TLS_SERVER_ONLY is not set
|
||||||
|
# CONFIG_MBEDTLS_TLS_CLIENT_ONLY is not set
|
||||||
|
# CONFIG_MBEDTLS_TLS_DISABLED is not set
|
||||||
|
CONFIG_MBEDTLS_TLS_SERVER=y
|
||||||
|
CONFIG_MBEDTLS_TLS_CLIENT=y
|
||||||
|
CONFIG_MBEDTLS_TLS_ENABLED=y
|
||||||
|
|
||||||
|
#
|
||||||
|
# TLS Key Exchange Methods
|
||||||
|
#
|
||||||
|
# CONFIG_MBEDTLS_PSK_MODES is not set
|
||||||
|
CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y
|
||||||
|
CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA=y
|
||||||
|
CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE=y
|
||||||
|
CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA=y
|
||||||
|
CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA=y
|
||||||
|
CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA=y
|
||||||
|
CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA=y
|
||||||
|
CONFIG_MBEDTLS_SSL_RENEGOTIATION=y
|
||||||
|
# CONFIG_MBEDTLS_SSL_PROTO_SSL3 is not set
|
||||||
|
CONFIG_MBEDTLS_SSL_PROTO_TLS1=y
|
||||||
|
CONFIG_MBEDTLS_SSL_PROTO_TLS1_1=y
|
||||||
|
CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y
|
||||||
|
# CONFIG_MBEDTLS_SSL_PROTO_DTLS is not set
|
||||||
|
CONFIG_MBEDTLS_SSL_ALPN=y
|
||||||
|
CONFIG_MBEDTLS_SSL_SESSION_TICKETS=y
|
||||||
|
|
||||||
|
#
|
||||||
|
# Symmetric Ciphers
|
||||||
|
#
|
||||||
|
CONFIG_MBEDTLS_AES_C=y
|
||||||
|
# CONFIG_MBEDTLS_CAMELLIA_C is not set
|
||||||
|
# CONFIG_MBEDTLS_DES_C is not set
|
||||||
|
CONFIG_MBEDTLS_RC4_DISABLED=y
|
||||||
|
# CONFIG_MBEDTLS_RC4_ENABLED_NO_DEFAULT is not set
|
||||||
|
# CONFIG_MBEDTLS_RC4_ENABLED is not set
|
||||||
|
# CONFIG_MBEDTLS_BLOWFISH_C is not set
|
||||||
|
# CONFIG_MBEDTLS_XTEA_C is not set
|
||||||
|
CONFIG_MBEDTLS_CCM_C=y
|
||||||
|
CONFIG_MBEDTLS_GCM_C=y
|
||||||
|
# CONFIG_MBEDTLS_RIPEMD160_C is not set
|
||||||
|
|
||||||
|
#
|
||||||
|
# Certificates
|
||||||
|
#
|
||||||
|
CONFIG_MBEDTLS_PEM_PARSE_C=y
|
||||||
|
CONFIG_MBEDTLS_PEM_WRITE_C=y
|
||||||
|
CONFIG_MBEDTLS_X509_CRL_PARSE_C=y
|
||||||
|
CONFIG_MBEDTLS_X509_CSR_PARSE_C=y
|
||||||
|
CONFIG_MBEDTLS_ECP_C=y
|
||||||
|
CONFIG_MBEDTLS_ECDH_C=y
|
||||||
|
CONFIG_MBEDTLS_ECDSA_C=y
|
||||||
|
CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED=y
|
||||||
|
CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED=y
|
||||||
|
CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=y
|
||||||
|
CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED=y
|
||||||
|
CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED=y
|
||||||
|
CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED=y
|
||||||
|
CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED=y
|
||||||
|
CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED=y
|
||||||
|
CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED=y
|
||||||
|
CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED=y
|
||||||
|
CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED=y
|
||||||
|
CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED=y
|
||||||
|
CONFIG_MBEDTLS_ECP_NIST_OPTIM=y
|
||||||
|
|
||||||
#
|
#
|
||||||
# OpenSSL
|
# OpenSSL
|
||||||
|
@ -331,6 +412,11 @@ CONFIG_OPENSSL_ASSERT_DO_NOTHING=y
|
||||||
# CONFIG_SPI_FLASH_ENABLE_COUNTERS is not set
|
# CONFIG_SPI_FLASH_ENABLE_COUNTERS is not set
|
||||||
CONFIG_SPI_FLASH_ROM_DRIVER_PATCH=y
|
CONFIG_SPI_FLASH_ROM_DRIVER_PATCH=y
|
||||||
|
|
||||||
|
#
|
||||||
|
# tcpip adapter
|
||||||
|
#
|
||||||
|
CONFIG_IP_LOST_TIMER_INTERVAL=120
|
||||||
|
|
||||||
#
|
#
|
||||||
# Wear Levelling
|
# Wear Levelling
|
||||||
#
|
#
|
||||||
|
|
Loading…
Reference in a new issue