Initial commit of firmware

This commit is contained in:
2025-04-12 13:30:57 +01:00
commit 264a3462e0
374 changed files with 332649 additions and 0 deletions

View File

@@ -0,0 +1,971 @@
/***************************************************************************//**
* @file
* @brief Memory Manager Driver API definition.
*******************************************************************************
* # License
* <b>Copyright 2024 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#ifndef SL_MEMORY_MANAGER_H_
#define SL_MEMORY_MANAGER_H_
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include "sl_status.h"
#include "sl_core.h"
#include "sl_memory_manager_region.h"
#ifdef __cplusplus
extern "C" {
#endif
/**************************************************************************//**
* @addtogroup memory_manager Memory Manager
*
* @details
* ## Overview
*
* The Memory Manager is a platform-level software module that provides different
* ways to perform runtime allocations, either one shot or dynamic.
* The Memory Manager complements the toolchain linker by managing the RAM memory
* not allocated/partitioned by the linker. It offers different constructs that
* will help the different Silicon Labs SDK software modules and your application
* to build, as much as possible, an efficient and optimized RAM layout. The main
* Memory Manager constructs will be:
* - A dynamic allocation API
* - A memory pool API
* - A dynamic reservation API
*
* The Memory Manager can be used in an RTOS context as it is thread-safe by
* protecting adequately its internal shared resources.
*
* ## Initialization
*
* The initialization part includes the following configuration files:
* - \b sl_memory_manager_region_config.h
* - \b sl_memory_manager_config.h
*
* These header files offer a few configurations for the Memory Manager.
* They use the CMSIS Configuration Wizard Annotations that can be rendered
* by Simplicity Studio to set graphically the configuration settings value.
*
* The API function sl_memory_init() is used to initialize the Memory Manager
* module. This function must be called early during your initialization sequence.
* If the SL System component (@ref system) is used by your application, the
* sl_memory_init() call will be added automatically to your initialization
* sequence.
*
* \a sl_memory_manager_region_config.h allows to configure the stack size for
* the application. The default value of 4096 bytes for SL_STACK_SIZE will
* be used by the linker to allocate a stack zone in the RAM. In a baremetal
* application, the stack size is bound to the value set by SL_STACK_SIZE.
* So you should carefully size the stack in that case.
* In an RTOS application, the stack size SL_STACK_SIZE will serve mainly for the
* code running in the main() context until the kernel is launched. Once the kernel is
* started, the different tasks' stacks, created upon tasks' creation, will allow
* to save the different contexts (that is task, function, ISR contexts). The main
* stack will be less active while the application's tasks are running.
*
* @note It is not possible to specify a minimum heap size via a configuration value
* in \a sl_memory_manager_region_config.h. The GCC and IAR linker files define
* a heap section in RAM that will be the last zone of the RAM partitioned by
* the toolchain linker. The size of this heap zone will be the remaining
* space of the RAM. If you need to perform some checks on the heap size, you
* should do it at runtime using the Memory Manager \ref subsubsection-statistics
* "statistics API". You cannot do it during the toolchain preprocessor time.
*
* ## Functionalities
*
* The Memory Manager offers different functionalities such as:
* - Dynamically allocating and freeing blocks.
* - Creating and deleting memory pools. Allocating and freeing fixed-size
* blocks from a given pool.
* - Reserving and releasing blocks.
* - Getting statistics about the heap usage and the stack.
* - Retargeting the standard C library memory functions malloc()/free()/
* calloc()/realloc() to the Memory Manager ones.
* - Overloading the C++ standard new/delete operators to the Memory Manager
* malloc()/free()
*
* \subsubsection subsubsection-dynamic-allocation Dynamic Allocation
* The dynamic allocation API allows to dynamically allocate and free memory blocks
* of various sizes. The API supports the classic signatures of memory functions
* malloc()/free()/calloc()/realloc() while also offering variants of the same
* functions.
*
* <table>
* <tr><th>Operation<th>Standard-Like Function<th>Variant Function
* <tr><td>Allocating a block<td>sl_malloc()<td>
* <ul>
* <li>sl_memory_alloc()
* <li>sl_memory_alloc_advanced()
* </ul>
* <tr><td>Freeing a block<td>sl_free()<td>sl_memory_free()
* <tr><td>Allocating a block whose content is zero'ed<td>sl_calloc()<td>sl_memory_calloc()
* <tr><td>Re-allocating a block<td>sl_realloc()<td>sl_memory_realloc()
* </table>
*
* The variants functions \a sl_memory_xxxx() differs from the standard-like functions
* with the following:
* - They return an error code of type \a sl_status_t. You may want
* to process any returned error code different from \a SL_STATUS_OK.
* - They allow to specify a block alignment requirement in bytes. The alignment
* can be any power-of-two values between 1 and 512 bytes inclusively. The default
* block alignment the Memory Manager will use is 8 bytes to maximize CPU accesses
* to allocated memory blocks.
* - They allow to specify a block type as long-term or short-term (further explained
* below). The Memory Manager allows to allocate a block from different ends of the heap
* to limit the fragmentation.
*
* Allocating a block can be done by specifying your requested size with the simple
* sl_malloc(). If you have a special alignment requirement, the function
* sl_memory_alloc_advanced() is the one to use.
* The Memory Manager will use a first fit algorithm to find the block fitting
* the requested size. If the found block is too large, the allocator tries to split it
* to create a new free block from the unwanted portion of the found block. The block
* internal split operation helps to limit the internal fragmentation.
*
* The dynamic allocation API allows to specify the block type as long-term
* (BLOCK_TYPE_LONG_TERM) or short-term (BLOCK_TYPE_SHORT_TERM) with the
* functions sl_memory_alloc() or sl_memory_alloc_advanced().
* The long-term (LT) allocations are allocated from the heap start,
* while short-term (ST) ones are allocated from the heap end. LT/ST allocations
* relate to the expected lifetime of the block allocation. LT blocks are used for
* the full duration of the application or for something that is expected
* to last a long time. For instance, a control data structure enabling the proper
* functioning of a stack's layer, a driver, a part of the application layer.
* ST blocks are used for something that is expected to be freed quite quickly.
* For example, a received buffer that needs to be processed and once processed
* will be freed.
* Grouping your allocations as LT blocks and/or ST blocks can help to limit the
* heap fragmentation.
* Certain functions does not allow to indicate the block type. In that case,
* a default type is selected by the allocator.
*
* <table>
* <tr><th>Function<th>Block type
* <tr><td>sl_malloc()<td>Long-term by default<td>
* <tr><td>sl_memory_alloc()<td>Long-term or short-term<td>
* <tr><td>sl_memory_alloc_advanced()<td>Long-term or short-term<td>
* <tr><td>sl_calloc()<td>Long-term by default<td>
* <tr><td>sl_memory_calloc()<td>Long-term or short-term<td>
* <tr><td>sl_realloc()<td>Long-term by default<td>
* <tr><td>sl_memory_realloc()<td>Long-term by default<td>
* </table>
*
* Freeing a block is done by calling sl_free() or sl_memory_free(). sl_memory_free()
* returns an error code of type sl_status_t that you may want to test. Passing a NULL
* pointer to sl_free() or sl_memory_free() results in a neutral situation where the
* free() function will do nothing. If the same block is freed twice, the function
* sl_memory_free() will return an error. During the free operation, the function will
* try to merge adjacent blocks to the block that is being freed in order to limit
* the internal fragmentation. The adjacent blocks must, of course, not be in use
* to be merged.
*
* If you want to get a block from the heap whose content has been initialized to zero
* to avoid any garbage values, the function sl_calloc() or sl_memory_calloc() can be
* called.
*
* If you need to reallocate a block, the function sl_realloc() or sl_memory_realloc()
* should be called. Both versions allow to:
* - Extend the block with the requested size greater than the original size.
* - Reduce the block with the requested size smaller than the original size.
* - Extend a different block with the requested size greater than the original size.
*
* The block can be moved elsewhere in the heap if it is impossible to extend it in its
* current memory space. A reduced block will always stay in the original block space as the
* allocator does not need to provide a different block.
* The content of the reallocated memory block is preserved up to the lesser of the
* new and old sizes, even if the block is moved to a new location. If the new size
* is larger, the value of the newly allocated portion is indeterminate.
* Some combinations of input parameters when calling sl_realloc() or sl_memory_realloc()
* will lead to the same behavior as sl_malloc(), sl_memory_alloc() or sl_free(),
* sl_memory_free() (cf. the sl_realloc() or sl_memory_realloc() function description
* for more details about those combinations).
*
* The following code snippet shows a basic block allocation and
* deallocation using the standard-like functions:
* @code{.c}
* uint8_t *ptr8;
*
* ptr8 = (uint8_t *)sl_malloc(200);
* memset(ptr8, 0xAA, 100);
* sl_free(ptr8);
* @endcode
*
* This other code snippet shows the same basic block allocation and
* deallocation using the variant functions:
* @code{.c}
* uint8_t *ptr8;
* sl_status_t status;
*
* status = sl_memory_alloc(100, BLOCK_TYPE_LONG_TERM, (void **)&ptr8);
* if (status != SL_STATUS_OK) {
* // Process the error condition.
* }
*
* memset(ptr8, 0xBB, 100);
*
* status = sl_memory_free(ptr8);
* if (status != SL_STATUS_OK) {
* // Process the error condition.
* }
* @endcode
*
* ### Memory Pool
*
* The memory pool API allows to:
* - Create a pool composed of N number of fixed-size blocks: sl_memory_create_pool().
* - Delete a pool: sl_memory_delete_pool().
* - Get a block from the pool: sl_memory_pool_alloc().
* - Free a pool's block: sl_memory_pool_free().
*
* Memory pools are convenient if you want to ensure a sort of guaranteed quotas
* for some memory allocations situations. It is also more robust to unexpected
* allocations errors as opposed to the dynamic allocation API in which a block
* allocation can fail randomly if there is no free block to satisfy the requested
* size.
*
* The memory pool API uses a pool handle. This handle is initialized when the pool
* is created with sl_memory_create_pool(). Then this handle is passed as an input
* parameter of the other functions. The handle can be allocated statically or
* dynamically. A static pool handle means the handle of type
* @ref sl_memory_pool_t "sl_memory_pool_t{}" is a global variable for example.
* A dynamic pool handle means the handle is obtained from the heap itself by
* calling the function sl_memory_pool_handle_alloc().The dynamic pool handle will
* be freed with a call to sl_memory_pool_handle_free().
*
* The following code snippet shows a typical memory pool API sequence using
* a static pool handle:
* @code{.c}
* uint8_t *ptr8;
* sl_status_t status;
* sl_memory_pool_t pool1_handle = { 0 };
*
* // Create a pool of 15 blocks whose size is 100 bytes for each block.
* status = sl_memory_create_pool(100, 15, &pool1_handle);
* if (status != SL_STATUS_OK) {
* // Process the error condition.
* }
*
* status = sl_memory_pool_alloc(&pool1_handle, (void **)&ptr8);
* if (status != SL_STATUS_OK) {
* // Process the error condition.
* }
*
* memset(ptr8, 0xCC, 100);
*
* status = sl_memory_pool_free(&pool1_handle, ptr8);
* if (status != SL_STATUS_OK) {
* // Process the error condition.
* }
*
* status = sl_memory_delete_pool(&pool1_handle);
* if (status != SL_STATUS_OK) {
* // Process the error condition.
* }
* @endcode
*
* This other code snippet presents the previous typical memory pool API sequence
* using a dynamic pool handle:
* @code{.c}
* sl_status_t status;
* sl_memory_pool_t *pool1_handle = NULL;
*
* status = sl_memory_pool_handle_alloc(&pool1_handle);
* if (status != SL_STATUS_OK) {
* // Process the error condition.
* }
*
* // Create a pool of 15 blocks of 100 bytes in size.
* status = sl_memory_create_pool(100, 15, &pool1_handle);
* if (status != SL_STATUS_OK) {
* // Process the error condition.
* }
*
* // Get blocks from the pool, use them and free them once done.
* ...
*
* status = sl_memory_delete_pool(&pool1_handle);
* if (status != SL_STATUS_OK) {
* // Process the error condition.
* }
*
* status = sl_memory_pool_handle_free(pool1_handle);
* if (status != SL_STATUS_OK) {
* // Process the error condition.
* }
* @endcode
*
* ### Dynamic Reservation
*
* The dynamic reservation is a special construct allowing to reserve a block
* of a given size with sl_memory_reserve_block() and to release it with
* sl_memory_release_block(). The reserved block can then be used to any
* application purposes. The reserved block will be taken from the
* short-term section at the end of the heap.
* Please note that the dynamic reservation API is not meant
* to be used in the same way as the \ref subsubsection-dynamic-allocation
* "dynamic allocation API".
*
* The dynamic reservation API uses a reservation handle. This handle is initialized
* when the block is reserved with sl_memory_reserve_block(). Then this handle
* is passed as an input parameter to the other functions. The handle can be
* allocated statically or dynamically. A static reservation handle means the handle
* of type @ref sl_memory_reservation_t "sl_memory_reservation_t{}" is a global
* variable for example. A dynamic reservation handle means the handle is
* obtained from the heap itself by calling the function
* sl_memory_reservation_handle_alloc(). The dynamic reservaiton handle will be
* freed with a call to sl_memory_reservation_handle_free().
*
* The following code snippet shows a typical dynamic reservation API sequence
* using a static reservation handle:
* @code{.c}
* uint8_t *ptr8;
* sl_status_t status;
* sl_memory_reservation_t reservation_handle1 = { 0 };
*
* status = sl_memory_reserve_block(1024,
* SL_MEMORY_BLOCK_ALIGN_8_BYTES,
* reservation_handle1,
* (void **)&ptr8);
* if (status != SL_STATUS_OK) {
* // Process the error condition.
* }
*
* memset(ptr8, 0xDD, 1024);
*
* status = sl_memory_release_block(&reservation_handle1);
* if (status != SL_STATUS_OK) {
* // Process the error condition.
* }
* @endcode
*
* This other code snippet demonstrates the previous typical dynamic reservation API
* sequence using a dynamic reservation handle:
* @code{.c}
* uint8_t *ptr8;
* sl_status_t status;
* sl_memory_reservation_t *reservation_handle1;
*
* status = sl_memory_reservation_handle_alloc(&reservation_handle1);
* if (status != SL_STATUS_OK) {
* // Process the error condition.
* }
*
* status = sl_memory_reserve_block(1024,
* SL_MEMORY_BLOCK_ALIGN_8_BYTES,
* reservation_handle1,
* (void **)&ptr8);
* if (status != SL_STATUS_OK) {
* // Process the error condition.
* }
*
* memset(ptr8, 0xEE, 1024);
*
* status = sl_memory_release_block(&reservation_handle1);
* if (status != SL_STATUS_OK) {
* // Process the error condition.
* }
*
* status = sl_memory_reservation_handle_free(reservation_handle1);
* if (status != SL_STATUS_OK) {
* // Process the error condition.
* }
* @endcode
*
* \subsubsection subsubsection-statistics Statistics
*
* As your code is allocating and freeing blocks, you may want to know at a certain
* instant what the current state of the heap is. Some heap statistics queries at
* runtime can help to understand the current usage of the heap. By using the
* following statistics functions, you may be able to perform some asynchronous
* runtime heap checks:
* - Total heap size: sl_memory_get_total_heap_size().
* - Current free heap size: sl_memory_get_free_heap_size().
* - Current used heap size: sl_memory_get_used_heap_size().
* - Highest accumulated heap size usage: sl_memory_get_heap_high_watermark().
* - You can reset the high heap usage watermark with
* sl_memory_reset_heap_high_watermark().
*
* Besides a few functions each dedicated to a specific statistic, the function
* sl_memory_get_heap_info() allows to get a general heap information structure
* of type @ref sl_memory_heap_info_t "sl_memory_heap_info_t{}" with several heap
* statistics. Some of them overlap the statistics returned by the dedicated
* functions while the others complements statistics returned by the dedicated
* functions. Refer to the description of @ref sl_memory_heap_info_t
* "sl_memory_heap_info_t{}" for more information of each field.
*
* If you want to know the start address and the total size of the program's
* stack and/or heap, simply call respectively the function sl_memory_get_stack_region()
* and/or sl_memory_get_heap_region().
*
* ### C/C++ Toolchains Standard Memory Functions Retarget/Overload
*
* A program can perform dynamic memory allocations and deallocations using the
* standard memory functions whose implementation is provided by the C or C++
* toolchain libraries.
* - C toolchain for the classic malloc()/free()/calloc()/realloc()
* - C++ toolchain for the new/delete operators
*
* The Memory Manager supports the C standard memory functions retarget and the C++
* new/delete overload.
*
* When the \b memory_manager component is installed, the C standard memory
* functions are automatically retargeted to the Memory Manager ones:
* - GCC: coupled to the linker option "--wrap", the functions retargeted are
* - standard _malloc_r() -> sl_malloc()
* - standard _free_r() -> sl_free()
* - standard _calloc_r() -> sl_calloc()
* - standard _realloc_r() -> sl_realloc()
* - IAR: it has three separate heap memory handlers (the basic, the advanced,
* and the no-free heap handlers). IAR generally auto-selects one of the handlers.
* - Basic heap
* - standard __basic_malloc() -> sl_malloc()
* - standard __basic_free() -> sl_free()
* - standard __basic_calloc() -> sl_calloc()
* - standard __basic_realloc() -> sl_realloc()
* - Advanced heap
* - standard __iar_dl_malloc() -> sl_malloc()
* - standard __iar_dl_free() -> sl_free()
* - standard __iar_dl_calloc() -> sl_calloc()
* - standard __iar_dl_realloc() -> sl_realloc()
* - No Free heap
* - standard __no_free_malloc() -> sl_malloc()
* - standard __no_free_calloc() -> sl_calloc()
*
* If you need the C++ new/delete global overload calling sl_memory_alloc() and
* sl_memory_free(), please install the additional component
* \b memory_manager_cpp.
* This global overload of new/delete operators will also apply to any C++
* standard containers (for example vector, string, list).
*
* @note The Silicon Labs SDK generates a GCC or IAR linker script with Simplicity
* Studio. A typical toolchain linker script will define a section called "heap"
* or "HEAP". Usually, the C memory standard functions will assume a linker-defined
* "heap" section exists. If the memory_manager component is present, the
* toolchain linker script will define a new heap section named "memory_manager_heap"
* or "MEMORY_MANAGER_HEAP". Since the Memory Manager retargets the standard
* function malloc()/free()/calloc()/realloc() to the Memory Manager ones, there
* should not be any issues in your program. If an unlikely situation occurs where
* the toolchain standard memory functions retarget does not work, your application
* might end up calling a standard malloc() implementation from the
* toolchain instead of the Memory Manager one. In that case, a runtime
* error can occur and it is expected. You should then review the project settings
* to detect why the Memory Manager retarget did not work properly.
*
* ## Hints
* ### Memory Allocations from ISR
*
* In general, ISR must be kept short. Allocating and freeing blocks from an ISR is
* possible but you should be careful. Nothing really prevents you from calling the
* dynamic allocation API functions such as sl_malloc() and sl_free(). But keep in
* mind a few things with the dynamic allocation API:
* - The dynamic allocation API functions protect their internal resources
* such as global lists managing the heap metadata by using critical sections.
* So when in your ISR, you will disable interrupts for a certain period of time,
* preventing other interrupts to be processed in time if your application has hard
* real-time constraints. This increases the overall interrupt latency of your
* system if this ISR executes very often to perform a dynamic memory operation
* - They can introduce non-deterministic behavior which is undesirable if your
* application requires crucial precise timing
* - A function such as sl_malloc() can fail if there is no block to satisfy
* your requested size allocation. Implementing the proper error handling in the
* ISR may increase the time spent in the ISR.
*
* In the end, it really depends of your ISR processing context doing memory
* allocations/deallocations. If you really need to perform dynamic allocation from
* ISR, it may be better at least to use a memory pool. Getting and releasing a block
* from a pool is an operation more deterministic. And if you have properly
* sized your pool with a number of available blocks, you are less likely to
* encounter an allocation error.
*
* @{
*****************************************************************************/
// ----------------------------------------------------------------------------
// DEFINES
/// Special value to indicate the default block alignment to the Memory Manager
/// allocator. 8 bytes is the minimum alignment to account for largest CPU data
/// type that can be used in some block allocation scenarios.
#define SL_MEMORY_BLOCK_ALIGN_DEFAULT 0xFFFFFFFFU
/// Pre-defined values for block alignment managed by the Memory Manager allocator.
#define SL_MEMORY_BLOCK_ALIGN_8_BYTES 8U ///< 8 bytes alignment.
#define SL_MEMORY_BLOCK_ALIGN_16_BYTES 16U ///< 16 bytes alignment.
#define SL_MEMORY_BLOCK_ALIGN_32_BYTES 32U ///< 32 bytes alignment.
#define SL_MEMORY_BLOCK_ALIGN_64_BYTES 64U ///< 64 bytes alignment.
#define SL_MEMORY_BLOCK_ALIGN_128_BYTES 128U ///< 128 bytes alignment.
#define SL_MEMORY_BLOCK_ALIGN_256_BYTES 256U ///< 256 bytes alignment.
#define SL_MEMORY_BLOCK_ALIGN_512_BYTES 512U ///< 512 bytes alignment.
// ----------------------------------------------------------------------------
// DATA TYPES
/// @brief Block type.
typedef enum {
BLOCK_TYPE_LONG_TERM = 0, ///< Long-term block type.
BLOCK_TYPE_SHORT_TERM = 1 ///< Short-term block type.
} sl_memory_block_type_t;
/// @brief General purpose heap information.
typedef struct {
uint32_t base_addr; ///< Heap base address.
size_t used_size; ///< Used size (in bytes), independently of alignment.
size_t free_size; ///< Free size (in bytes), independently of alignment.
size_t total_size; ///< Total heap size (in bytes).
size_t free_block_count; ///< Number of free blocks.
size_t free_block_largest_size; ///< Largest free block size (in bytes).
size_t free_block_smallest_size; ///< Smallest free block size (in bytes).
size_t used_block_count; ///< Number of used blocks.
size_t used_block_largest_size; ///< Largest used block size (in bytes).
size_t used_block_smallest_size; ///< Smallest used block size (in bytes).
} sl_memory_heap_info_t;
/// @brief Memory block reservation handle.
typedef struct {
void *block_address; ///< Reserved block base address.
size_t block_size; ///< Reserved block size (in bytes).
} sl_memory_reservation_t;
/// @brief Memory pool handle.
typedef struct {
#if defined(SL_MEMORY_POOL_POWER_AWARE)
sl_memory_reservation_t *reservation; ///< Pointer to reservation handle.
#else
void *block_address; ///< Reserved block base address.
#endif
uint32_t *block_free; ///< Pointer to pool's free blocks list.
size_t block_count; ///< Max quantity of blocks in the pool.
size_t block_size; ///< Size of each block.
} sl_memory_pool_t;
// ----------------------------------------------------------------------------
// PROTOTYPES
/***************************************************************************//**
* Initializes the memory manager.
*
* @return SL_STATUS_OK if successful. Error code otherwise.
*
* @note This function should only be called once.
******************************************************************************/
sl_status_t sl_memory_init(void);
/***************************************************************************//**
* Reserves a memory block that will never need retention in EM2.
*
* @param[in] size Size of the block, in bytes.
* @param[in] align Required alignment for the block, in bytes.
* @param[out] block Pointer to variable that will receive the start address
* of the allocated block. NULL in case of error condition.
*
* @return SL_STATUS_OK if successful. Error code otherwise.
*
* @note Required alignment of memory block (in bytes) MUST be a power of 2
* and can range from 1 to 512 bytes.
* The define SL_MEMORY_BLOCK_ALIGN_DEFAULT can be specified to select
* the default alignment.
******************************************************************************/
sl_status_t sl_memory_reserve_no_retention(size_t size,
size_t align,
void **block);
/***************************************************************************//**
* Allocates a memory block of at least requested size from the heap. Simple
* version.
*
* @param[in] size Size of the block, in bytes.
*
* @return Pointer to allocated block if successful. Null pointer if
* allocation failed.
*
* @note Requesting a block of 0 byte will return a null pointer.
*
* @note All allocated blocks using this function will be considered long-term
* allocations.
******************************************************************************/
void *sl_malloc(size_t size);
/***************************************************************************//**
* Dynamically allocates a block of memory.
*
* @param[in] size Size of the block, in bytes.
* @param[in] type Type of block (long-term or short-term).
* BLOCK_TYPE_LONG_TERM
* BLOCK_TYPE_SHORT_TERM
* @param[out] block Pointer to variable that will receive the start address
* of the allocated block. NULL in case of error condition.
*
* @return SL_STATUS_OK if successful. Error code otherwise.
******************************************************************************/
sl_status_t sl_memory_alloc(size_t size,
sl_memory_block_type_t type,
void **block);
/***************************************************************************//**
* Dynamically allocates a block of memory. Advanced version that allows to
* specify alignment.
*
* @param[in] size Size of the block, in bytes.
* @param[in] align Required alignment for the block, in bytes.
* @param[in] type Type of block (long-term or short term).
* BLOCK_TYPE_LONG_TERM
* BLOCK_TYPE_SHORT_TERM
* @param[out] block Pointer to variable that will receive the start address
* of the allocated block. NULL in case of error condition.
*
* @return SL_STATUS_OK if successful. Error code otherwise.
*
* @note Required alignment of memory block (in bytes) MUST be a power of 2
* and can range from 1 to 512 bytes.
* The define SL_MEMORY_BLOCK_ALIGN_DEFAULT can be specified to select
* the default alignment.
******************************************************************************/
sl_status_t sl_memory_alloc_advanced(size_t size,
size_t align,
sl_memory_block_type_t type,
void **block);
/***************************************************************************//**
* Frees a previously allocated block back into the heap. Simple version.
*
* @param[in] ptr Pointer to memory block to be freed.
*
* @note Passing a null pointer does nothing.
******************************************************************************/
void sl_free(void *ptr);
/***************************************************************************//**
* Frees a dynamically allocated block of memory.
*
* @param[in] block Pointer to the block that must be freed.
*
* @return SL_STATUS_OK if successful. Error code otherwise.
******************************************************************************/
sl_status_t sl_memory_free(void *block);
/***************************************************************************//**
* Dynamically allocates a block of memory cleared to 0. Simple version.
*
* @param[in] item_count Number of elements to be allocated.
* @param[in] size Size of each elements, in bytes.
*
* @return Pointer to allocated block if successful. Null pointer if
* allocation failed.
*
* @note All allocated blocks using this function will be considered long-term
* allocations.
******************************************************************************/
void *sl_calloc(size_t item_count,
size_t size);
/***************************************************************************//**
* Dynamically allocates a block of memory cleared to 0.
*
* @param[in] item_count Number of elements to be allocated.
* @param[in] size Size of each elements, in bytes.
* @param[in] type Type of block (long-term or short-term).
* BLOCK_TYPE_LONG_TERM
* BLOCK_TYPE_SHORT_TERM
* @param[out] block Pointer to variable that will receive the start
* address of the allocated block. NULL in case of
* error condition.
*
* @return SL_STATUS_OK if successful. Error code otherwise.
******************************************************************************/
sl_status_t sl_memory_calloc(size_t item_count,
size_t size,
sl_memory_block_type_t type,
void **block);
/***************************************************************************//**
* Resizes a previously allocated memory block. Simple version.
*
* @param[in] ptr Pointer to the allocation to resize. If NULL, behavior
* is same as sl_malloc(), sl_memory_alloc().
* @param[in] size New size of the block, in bytes. If 0, behavior is same as
* sl_free(), sl_memory_free().
*
* @return Pointer to newly allocated block, if successful. Null pointer if
* re-allocation failed.
*
* @note All re-allocated blocks using this function will be considered
* long-term allocations.
*
* @note 'ptr' NULL and 'size' of 0 bytes is an incorrect parameters
* combination. No reallocation will be done by the function as it is
* an error condition.
*
* @note If the new 'size' is the same as the old, the function changes nothing
* and returns the same provided address 'ptr'.
******************************************************************************/
void *sl_realloc(void *ptr,
size_t size);
/***************************************************************************//**
* Resizes a previously allocated memory block.
*
* @param[in] ptr Pointer to the allocation to resize. If NULL, behavior
* is same as sl_malloc(), sl_memory_alloc().
* @param[in] size New size of the block, in bytes. If 0, behavior is same as
* sl_free(), sl_memory_free().
* @param[out] block Pointer to variable that will receive the start address of
* the new allocated memory. NULL in case of error condition.
*
* @return SL_STATUS_OK if successful. Error code otherwise.
*
* @note All re-allocated blocks using this function will be considered
* long-term allocations.
*
* @note 'ptr' NULL and 'size' of 0 bytes is an incorrect parameters
* combination. No reallocation will be done by the function as it is
* an error condition.
*
* @note If the new 'size' is the same as the old, the function changes nothing
* and returns the same provided address 'ptr'.
******************************************************************************/
sl_status_t sl_memory_realloc(void *ptr,
size_t size,
void **block);
/***************************************************************************//**
* Dynamically reserves a block of memory.
*
* @param[in] size Size of the block, in bytes.
* @param[in] align Required alignment for the block, in bytes.
* @param[in] handle Handle to the reserved block.
* @param[out] block Pointer to variable that will receive the start address
* of the allocated block. NULL in case of error condition.
*
* @return SL_STATUS_OK if successful. Error code otherwise.
*
* @note Required alignment of memory block (in bytes) MUST be a power of 2
* and can range from 1 to 512 bytes.
* The define SL_MEMORY_BLOCK_ALIGN_DEFAULT can be specified to select
* the default alignment.
******************************************************************************/
sl_status_t sl_memory_reserve_block(size_t size,
size_t align,
sl_memory_reservation_t *handle,
void **block);
/***************************************************************************//**
* Frees a dynamically reserved block of memory.
*
* @param[in] handle Handle to the reserved block.
*
* @return SL_STATUS_OK if successful. Error code otherwise.
******************************************************************************/
sl_status_t sl_memory_release_block(sl_memory_reservation_t *handle);
/***************************************************************************//**
* Dynamically allocates a block reservation handle.
*
* @param[out] handle Handle to the reserved block.
*
* @return SL_STATUS_OK if successful. Error code otherwise.
******************************************************************************/
sl_status_t sl_memory_reservation_handle_alloc(sl_memory_reservation_t **handle);
/***************************************************************************//**
* Frees a dynamically allocated block reservation handle.
*
* @param[in] handle Handle to the reserved block.
*
* @return SL_STATUS_OK if successful. Error code otherwise.
******************************************************************************/
sl_status_t sl_memory_reservation_handle_free(sl_memory_reservation_t *handle);
/***************************************************************************//**
* Gets the size of the memory reservation handle structure.
*
* @return Memory reservation handle structure's size in bytes.
******************************************************************************/
uint32_t sl_memory_reservation_handle_get_size(void);
/***************************************************************************//**
* Creates a memory pool.
*
* @param[in] block_size Size of each block, in bytes.
* @param[in] block_count Number of blocks in the pool.
* @param[in] pool_handle Handle to the memory pool.
*
* @note This function assumes the 'pool_handle' is provided by the caller:
* - either statically (e.g. as a global variable)
* - or dynamically by calling sl_memory_pool_handle_alloc().
*
* @return SL_STATUS_OK if successful. Error code otherwise.
******************************************************************************/
sl_status_t sl_memory_create_pool(size_t block_size,
uint32_t block_count,
sl_memory_pool_t *pool_handle);
/***************************************************************************//**
* Deletes a memory pool.
*
* @param[in] pool_handle Handle to the memory pool.
*
* @return SL_STATUS_OK if successful. Error code otherwise.
*
* @note All pool allocations need to be freed by calling sl_memory_pool_free()
* on each block before calling sl_memory_delete_pool().
*
* @note The pool_handle provided is neither freed or invalidated. It can be
* reused in a new call to sl_memory_create_pool() to create another pool.
******************************************************************************/
sl_status_t sl_memory_delete_pool(sl_memory_pool_t *pool_handle);
/***************************************************************************//**
* Allocates a block from a memory pool.
*
* @param[in] pool_handle Handle to the memory pool.
* @param[out] block Pointer to a variable that will receive the address
* of the allocated block. NULL in case of error
* condition.
*
* @return SL_STATUS_OK if successful. Error code otherwise.
******************************************************************************/
sl_status_t sl_memory_pool_alloc(sl_memory_pool_t *pool_handle,
void **block);
/***************************************************************************//**
* Frees a block from a memory pool.
*
* @param[in] pool_handle Handle to the memory pool.
* @param[in] block Pointer to the block to free.
*
* @return SL_STATUS_OK if successful. Error code otherwise.
******************************************************************************/
sl_status_t sl_memory_pool_free(sl_memory_pool_t *pool_handle,
void *block);
/***************************************************************************//**
* Dynamically allocates a memory pool handle.
*
* @param[out] pool_handle Handle to the memory pool.
*
* @return SL_STATUS_OK if successful. Error code otherwise.
******************************************************************************/
sl_status_t sl_memory_pool_handle_alloc(sl_memory_pool_t **pool_handle);
/***************************************************************************//**
* Frees a dynamically allocated memory pool handle.
*
* @param[in] pool_handle Handle to the memory pool.
*
* @return SL_STATUS_OK if successful. Error code otherwise.
******************************************************************************/
sl_status_t sl_memory_pool_handle_free(sl_memory_pool_t *pool_handle);
/***************************************************************************//**
* Gets the size of the memory pool handle structure.
*
* @return Memory pool handle structure's size.
******************************************************************************/
uint32_t sl_memory_pool_handle_get_size(void);
/***************************************************************************//**
* Gets the total count of blocks in a memory pool.
*
* @param[in] pool_handle Handle to the memory pool.
*
* @return Total number of blocks.
******************************************************************************/
uint32_t sl_memory_pool_get_total_block_count(const sl_memory_pool_t *pool_handle);
/***************************************************************************//**
* Gets the count of free blocks in a memory pool.
*
* @param[in] pool_handle Handle to the memory pool.
*
* @return Number of free blocks.
******************************************************************************/
uint32_t sl_memory_pool_get_free_block_count(const sl_memory_pool_t *pool_handle);
/***************************************************************************//**
* Gets the count of used blocks in a memory pool.
*
* @param[in] pool_handle Handle to the memory pool.
*
* @return Number of used blocks.
******************************************************************************/
uint32_t sl_memory_pool_get_used_block_count(const sl_memory_pool_t *pool_handle);
/***************************************************************************//**
* Populates an sl_memory_heap_info_t{} structure with the current status of
* the heap.
*
* @param[in] heap_info Pointer to structure that will receive further heap
* information data.
*
* @return SL_STATUS_OK if successful. Error code otherwise.
******************************************************************************/
sl_status_t sl_memory_get_heap_info(sl_memory_heap_info_t *heap_info);
/***************************************************************************//**
* Gets the total size of the heap.
*
* @return Heap's size in bytes.
******************************************************************************/
size_t sl_memory_get_total_heap_size(void);
/***************************************************************************//**
* Gets the current free heap size.
*
* @return Free heap size in bytes.
******************************************************************************/
size_t sl_memory_get_free_heap_size(void);
/***************************************************************************//**
* Gets the current used heap size.
*
* @return Used heap size in bytes.
******************************************************************************/
size_t sl_memory_get_used_heap_size(void);
/***************************************************************************//**
* Gets heap high watermark.
*
* @return Highest heap usage in bytes recorded.
******************************************************************************/
size_t sl_memory_get_heap_high_watermark(void);
/***************************************************************************//**
* Reset heap high watermark to the current heap used.
******************************************************************************/
void sl_memory_reset_heap_high_watermark(void);
/** @} (end addtogroup memory_manager) */
#ifdef __cplusplus
}
#endif
#endif /* SL_MEMORY_MANAGER_H_ */

View File

@@ -0,0 +1,77 @@
/***************************************************************************//**
* @file
* @brief Getters for Heap and stack.
*******************************************************************************
* # License
* <b>Copyright 2024 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#ifndef SL_MEMORY_MANAGER_REGION_H_
#define SL_MEMORY_MANAGER_REGION_H_
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* @addtogroup memory_manager Memory Manager
* @{
******************************************************************************/
// ----------------------------------------------------------------------------
// DATA TYPES
/// @brief Memory region structure.
typedef struct sl_memory_region_t {
void * addr; ///< Pointer to the beginning of the memory region. Can be NULL.
size_t size; ///< Size of this memory region.
} sl_memory_region_t;
// ----------------------------------------------------------------------------
// PROTOTYPES
/***************************************************************************//**
* Gets size and location of the stack.
*
* @return description of the region reserved for the C stack.
******************************************************************************/
sl_memory_region_t sl_memory_get_stack_region(void);
/***************************************************************************//**
* Gets size and location of the heap.
*
* @return description of the region reserved for the C heap.
******************************************************************************/
sl_memory_region_t sl_memory_get_heap_region(void);
/** @} end addtogroup memory_manager) */
#ifdef __cplusplus
}
#endif
#endif /* SL_MEMORY_MANAGER_REGION_H_ */