From f57d7a9ac5954dd6ffc139f682e389da5b6f46df Mon Sep 17 00:00:00 2001 From: Santiago Lo Coco Date: Mon, 27 Sep 2021 16:26:28 -0300 Subject: [PATCH] Add MM based on FRTOS Co-authored-by: Ezequiel Bellver Co-authored-by: Juan Barmasch --- Kernel/memManagerFRT2.c | 347 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 347 insertions(+) create mode 100644 Kernel/memManagerFRT2.c diff --git a/Kernel/memManagerFRT2.c b/Kernel/memManagerFRT2.c new file mode 100644 index 0000000..d20112c --- /dev/null +++ b/Kernel/memManagerFRT2.c @@ -0,0 +1,347 @@ +/* + * A sample implementation of pvPortMalloc() and vPortFree() that permits + * allocated blocks to be freed, but does not combine adjacent free blocks + * into a single larger block (and so will fragment memory). See heap_4.c for + * an equivalent that does combine adjacent blocks into single larger blocks. + * + * See heap_1.c, heap_3.c and heap_4.c for alternative implementations, and the + * memory management pages of http://www.FreeRTOS.org for more information. + */ +#include +#include +#include +#include + +/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining +all the API functions to use the MPU wrappers. That should only be done when +task.h is included from an application file. */ +#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +// #include "FreeRTOS.h" +// #include "task.h" + +#define portCHAR char +#define portFLOAT float +#define portDOUBLE double +#define portLONG long +#define portSHORT short +#define portSTACK_TYPE uint32_t +#define portBASE_TYPE long + +typedef portSTACK_TYPE StackType_t; +typedef long BaseType_t; +typedef unsigned long UBaseType_t; + +/* Memory allocation related definitions. */ +#define configSUPPORT_STATIC_ALLOCATION 1 +#define configSUPPORT_DYNAMIC_ALLOCATION 1 +#define configTOTAL_HEAP_SIZE 1024 +#define configAPPLICATION_ALLOCATED_HEAP 0 +#define portBYTE_ALIGNMENT 8 +#define portBYTE_ALIGNMENT_MASK ( 0x0007 ) // 8 +#define pdFALSE ( ( BaseType_t ) 0 ) +#define pdTRUE ( ( BaseType_t ) 1 ) +#define portPOINTER_SIZE_TYPE uint32_t + +/* +#ifndef configHEAP_ALLOCATION_SCHEME +#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + #warning The configHEAP_ALLOCATION_SCHEME is not defined in FreeRTOSConfig +#endif +#else +#if(configHEAP_ALLOCATION_SCHEME == HEAP_ALLOCATION_TYPE2) + +#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE + +#if( configSUPPORT_DYNAMIC_ALLOCATION == 0 ) + #error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0 +#endif +*/ + +/* A few bytes might be lost to byte aligning the heap start address. */ +#define configADJUSTED_HEAP_SIZE ( configTOTAL_HEAP_SIZE - portBYTE_ALIGNMENT ) + +/* + * Initialises the heap structures before their first use. + */ +static void prvHeapInit( void ); + +/* Allocate the memory for the heap. */ +#if( configAPPLICATION_ALLOCATED_HEAP == 1 ) + /* The application writer has already defined the array used for the RTOS + heap - probably so it can be placed in a special segment or address. */ + extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ]; +#else + static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ]; +#endif /* configAPPLICATION_ALLOCATED_HEAP */ + + +/* Define the linked list structure. This is used to link free blocks in order +of their size. */ +typedef struct A_BLOCK_LINK +{ + struct A_BLOCK_LINK *pxNextFreeBlock; /*<< The next free block in the list. */ + size_t xBlockSize; /*<< The size of the free block. */ +} BlockLink_t; + + +static const uint16_t heapSTRUCT_SIZE = ( ( sizeof ( BlockLink_t ) + ( portBYTE_ALIGNMENT - 1 ) ) & ~portBYTE_ALIGNMENT_MASK ); +#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( heapSTRUCT_SIZE * 2 ) ) + +/* Create a couple of list links to mark the start and end of the list. */ +static BlockLink_t xStart, xEnd; + +/* Keeps track of the number of free bytes remaining, but says nothing about +fragmentation. */ +static size_t xFreeBytesRemaining = configADJUSTED_HEAP_SIZE; + +/* STATIC FUNCTIONS ARE DEFINED AS MACROS TO MINIMIZE THE FUNCTION CALL DEPTH. */ + +/* + * Insert a block into the list of free blocks - which is ordered by size of + * the block. Small blocks at the start of the list and large blocks at the end + * of the list. + */ +#define prvInsertBlockIntoFreeList( pxBlockToInsert ) \ +{ \ +BlockLink_t *pxIterator; \ +size_t xBlockSize; \ + \ + xBlockSize = pxBlockToInsert->xBlockSize; \ + \ + /* Iterate through the list until a block is found that has a larger size */ \ + /* than the block we are inserting. */ \ + for( pxIterator = &xStart; pxIterator->pxNextFreeBlock->xBlockSize < xBlockSize; pxIterator = pxIterator->pxNextFreeBlock ) \ + { \ + /* There is nothing to do here - just iterate to the correct position. */ \ + } \ + \ + /* Update the list to include the block being inserted in the correct */ \ + /* position. */ \ + pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock; \ + pxIterator->pxNextFreeBlock = pxBlockToInsert; \ +} +/*-----------------------------------------------------------*/ +void *pvPortMalloc( size_t xWantedSize ) +{ +BlockLink_t *pxBlock, *pxPreviousBlock, *pxNewBlockLink; +static BaseType_t xHeapHasBeenInitialised = pdFALSE; +void *pvReturn = NULL; + + // vTaskSuspendAll(); + { + /* If this is the first call to malloc then the heap will require + initialisation to setup the list of free blocks. */ + if( xHeapHasBeenInitialised == pdFALSE ) + { + prvHeapInit(); + xHeapHasBeenInitialised = pdTRUE; + } + + /* The wanted size is increased so it can contain a BlockLink_t + structure in addition to the requested amount of bytes. */ + if( xWantedSize > 0 ) + { + xWantedSize += heapSTRUCT_SIZE; + + /* Ensure that blocks are always aligned to the required number of bytes. */ + if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0 ) + { + /* Byte alignment required. */ + xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ); + } + } + + if( ( xWantedSize > 0 ) && ( xWantedSize < configADJUSTED_HEAP_SIZE ) ) + { + /* Blocks are stored in byte order - traverse the list from the start + (smallest) block until one of adequate size is found. */ + pxPreviousBlock = &xStart; + pxBlock = xStart.pxNextFreeBlock; + while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) ) + { + pxPreviousBlock = pxBlock; + pxBlock = pxBlock->pxNextFreeBlock; + } + + /* If we found the end marker then a block of adequate size was not found. */ + if( pxBlock != &xEnd ) + { + /* Return the memory space - jumping over the BlockLink_t structure + at its start. */ + pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + heapSTRUCT_SIZE ); + + /* This block is being returned for use so must be taken out of the + list of free blocks. */ + pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock; + + /* If the block is larger than required it can be split into two. */ + if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE ) + { + /* This block is to be split into two. Create a new block + following the number of bytes requested. The void cast is + used to prevent byte alignment warnings from the compiler. */ + pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize ); + + /* Calculate the sizes of two blocks split from the single + block. */ + pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize; + pxBlock->xBlockSize = xWantedSize; + + /* Insert the new block into the list of free blocks. */ + prvInsertBlockIntoFreeList( ( pxNewBlockLink ) ); + } + + xFreeBytesRemaining -= pxBlock->xBlockSize; + } + } + + // traceMALLOC( pvReturn, xWantedSize ); + } + // ( void ) xTaskResumeAll(); + + // #if( configUSE_MALLOC_FAILED_HOOK == 1 ) + // { + // if( pvReturn == NULL ) + // { + // extern void vApplicationMallocFailedHook( void ); + // vApplicationMallocFailedHook(); + // } + // } + // #endif + + return pvReturn; +} +/*-----------------------------------------------------------*/ + +void vPortFree( void *pv ) +{ +uint8_t *puc = ( uint8_t * ) pv; +BlockLink_t *pxLink; + + if( pv != NULL ) + { + /* The memory being freed will have an BlockLink_t structure immediately + before it. */ + puc -= heapSTRUCT_SIZE; + + /* This unexpected casting is to keep some compilers from issuing + byte alignment warnings. */ + pxLink = ( void * ) puc; + + // vTaskSuspendAll(); + { + /* Add this block to the list of free blocks. */ + prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) ); + xFreeBytesRemaining += pxLink->xBlockSize; + // traceFREE( pv, pxLink->xBlockSize ); + } + // ( void ) xTaskResumeAll(); + } +} +/*-----------------------------------------------------------*/ + +size_t xPortGetFreeHeapSize( void ) +{ + return xFreeBytesRemaining; +} +/*-----------------------------------------------------------*/ + +void vPortInitialiseBlocks( void ) +{ + /* This just exists to keep the linker quiet. */ +} +/*-----------------------------------------------------------*/ + +static void prvHeapInit( void ) +{ +BlockLink_t *pxFirstFreeBlock; +uint8_t *pucAlignedHeap; + + /* Ensure the heap starts on a correctly aligned boundary. */ + pucAlignedHeap = ( uint8_t * ) ( ( ( portPOINTER_SIZE_TYPE ) &ucHeap[ portBYTE_ALIGNMENT ] ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) ); + + /* xStart is used to hold a pointer to the first item in the list of free + blocks. The void cast is used to prevent compiler warnings. */ + xStart.pxNextFreeBlock = ( void * ) pucAlignedHeap; + xStart.xBlockSize = ( size_t ) 0; + + /* xEnd is used to mark the end of the list of free blocks. */ + xEnd.xBlockSize = configADJUSTED_HEAP_SIZE; + xEnd.pxNextFreeBlock = NULL; + + /* To start with there is a single free block that is sized to take up the + entire heap space. */ + pxFirstFreeBlock = ( void * ) pucAlignedHeap; + pxFirstFreeBlock->xBlockSize = configADJUSTED_HEAP_SIZE; + pxFirstFreeBlock->pxNextFreeBlock = &xEnd; +} +/*-----------------------------------------------------------*/ + +// #endif /* #ifdef configHEAP_ALLOCATION_SCHEME */ +// #endif /* #if(configHEAP_ALLOCATION_SCHEME == HEAP_ALLOCATION_TYPE1) */ + +char testOne() { + void * alloc1 = pvPortMalloc(100); + void * alloc2 = pvPortMalloc(200); + void * alloc3 = pvPortMalloc(300); + + memset(alloc1, 1, 100); + memset(alloc2, 2, 200); + memset(alloc3, 3, 300); + + for (int i = 0; i < 600; i++) { + if (i < 100) { + assert(*((char *) alloc1+i) == 1); + } else if (i < 300) { + assert(*((char *) alloc2+i-100) == 2); + } else if (i < 600) { + assert(*((char *) alloc3+i-300) == 3); + } + } + + return EXIT_SUCCESS; +} + +static unsigned long int next = 1; +int rand(void) // RAND_MAX assumed to be 32767 +{ + next = next * 1103515245 + 12345; + return (unsigned int)(next/65536) % 32768; +} + +/* +char testTwo() { + void * ptr; + while (ptr != NULL){ + ptr = memMalloc((rand() % 2000) + 1); + if (!((char *) memoryManager->nextAddress >= memoryManager->initialAddress)) { + printStringLen(13, "allocRand1 -- ERROR", 31); + new_line(); + return EXIT_FAILURE; + } + if (!((char *) memoryManager->nextAddress <= memoryManager->initialAddress + MANAGED_MEMORY_SIZE)) { + printStringLen(13, "allocRand2 -- ERROR", 31); + new_line(); + return EXIT_FAILURE; + } + // if (!((char *) memoryManager->lastAddress >= memoryManager->initialAddress)) { + // } + // if (!((char *) memoryManager->lastAddress <= memoryManager->initialAddress + MANAGED_MEMORY_SIZE)) { + // } + } + + return EXIT_SUCCESS; + +} +*/ + +// char mem[1024]; + +int main() { + // initMemoryManager(mem); + if (testOne() == EXIT_FAILURE) + return EXIT_FAILURE; + // if (testTwo() == EXIT_FAILURE) + // return EXIT_FAILURE; +} \ No newline at end of file