You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
201 lines
8.5 KiB
201 lines
8.5 KiB
/* Copyright (C) Dave Nadler 2017, All Rights Reserved. */
|
|
#include "FreeRTOSConfig.h"
|
|
#if !defined(configUSE_HEAP_SCHEME) || (configUSE_HEAP_SCHEME==6)
|
|
/**
|
|
* \file heap_useNewlib.c
|
|
* \brief Wrappers required to use newlib malloc-family within FreeRTOS.
|
|
*
|
|
* \par Overview
|
|
* Route FreeRTOS memory management functions to newlib's malloc family.
|
|
* Thus newlib and FreeRTOS share memory-management routines and memory pool,
|
|
* and all newlib's internal memory-management requirements are supported.
|
|
*
|
|
* \author Dave Nadler
|
|
* \date 1-July-2017
|
|
*
|
|
* \see https://sourceware.org/newlib/libc.html#Reentrancy
|
|
* \see https://sourceware.org/newlib/libc.html#malloc
|
|
* \see https://sourceware.org/newlib/libc.html#index-_005f_005fenv_005flock
|
|
* \see https://sourceware.org/newlib/libc.html#index-_005f_005fmalloc_005flock
|
|
* \see https://sourceforge.net/p/freertos/feature-requests/72/
|
|
* \see http://www.billgatliff.com/newlib.html
|
|
* \see http://wiki.osdev.org/Porting_Newlib
|
|
* \see http://www.embecosm.com/appnotes/ean9/ean9-howto-newlib-1.0.html
|
|
*
|
|
*
|
|
* \copyright
|
|
* (c) Dave Nadler 2017, All Rights Reserved.
|
|
* Web: http://www.nadler.com
|
|
* email: drn@nadler.com
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification,
|
|
* are permitted provided that the following conditions are met:
|
|
*
|
|
* - Use or redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions, ALL ORIGINAL COMMENTS, and the following disclaimer.
|
|
*
|
|
* - Redistributions in binary form must reproduce the above copyright notice, this
|
|
* list of conditions and the following disclaimer in the documentation and/or
|
|
* other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <stdlib.h> // maps to newlib...
|
|
#include <malloc.h> // mallinfo...
|
|
#include <errno.h> // ENOMEM
|
|
|
|
#include "FreeRTOS.h" // defines public interface we're implementing here
|
|
#if !defined(configUSE_NEWLIB_REENTRANT) || (configUSE_NEWLIB_REENTRANT!=1)
|
|
#warning "#define configUSE_NEWLIB_REENTRANT 1 // Required for thread-safety of newlib sprintf, strtok, etc..."
|
|
// If you're *really* sure you don't need FreeRTOS's newlib reentrancy support, remove this warning...
|
|
#endif
|
|
#include "task.h"
|
|
|
|
// ================================================================================================
|
|
// External routines required by newlib's malloc (sbrk/_sbrk, __malloc_lock/unlock)
|
|
// ================================================================================================
|
|
|
|
#if 0 // suggested minimal implementation from https://sourceware.org/newlib/libc.html#Syscalls:
|
|
// sbrk: Increase program data space. As malloc and related functions depend on this,
|
|
// it is useful to have a working implementation. The following suffices for a standalone system;
|
|
// it exploits the symbol _end automatically defined by the GNU linker.
|
|
caddr_t sbrk(int incr) {
|
|
extern char _end; /* Defined by the linker */
|
|
static char *heap_end;
|
|
char *prev_heap_end;
|
|
if (heap_end == 0) {
|
|
heap_end = &_end;
|
|
}
|
|
prev_heap_end = heap_end;
|
|
if (heap_end + incr > stack_ptr) {
|
|
write (1, "Heap and stack collision\n", 25);
|
|
abort ();
|
|
}
|
|
heap_end += incr;
|
|
return (caddr_t) prev_heap_end;
|
|
}
|
|
#endif
|
|
#if 0 // Freescale implementation
|
|
caddr_t _sbrk(int incr)
|
|
{
|
|
extern char end __asm("end");
|
|
extern char heap_limit __asm("__HeapLimit");
|
|
static char *heap_end;
|
|
char *prev_heap_end;
|
|
if (heap_end == NULL)
|
|
heap_end = &end;
|
|
prev_heap_end = heap_end;
|
|
if (heap_end + incr > &heap_limit)
|
|
{
|
|
errno = ENOMEM;
|
|
return (caddr_t)-1;
|
|
}
|
|
heap_end += incr;
|
|
return (caddr_t)prev_heap_end;
|
|
}
|
|
#endif
|
|
|
|
#ifndef NDEBUG
|
|
static int totalBytesProvidedBySBRK = 0;
|
|
#endif
|
|
extern char configLINKER_HEAP_BASE_SYMBOL, configLINKER_HEAP_LIMIT_SYMBOL, configLINKER_HEAP_SIZE_SYMBOL; // make sure to define these symbols in linker command file
|
|
static int heapBytesRemaining = (int)&configLINKER_HEAP_SIZE_SYMBOL; // that's (&__HeapLimit)-(&__HeapBase)
|
|
|
|
//! sbrk/_sbrk version supporting reentrant newlib (depends upon above symbols defined by linker control file).
|
|
char * sbrk(int incr) {
|
|
static char *currentHeapEnd = &configLINKER_HEAP_BASE_SYMBOL;
|
|
vTaskSuspendAll(); // Note: safe to use before FreeRTOS scheduler started
|
|
char *previousHeapEnd = currentHeapEnd;
|
|
if (currentHeapEnd + incr > &configLINKER_HEAP_LIMIT_SYMBOL) {
|
|
#if( configUSE_MALLOC_FAILED_HOOK == 1 )
|
|
{
|
|
extern void configUSE_MALLOC_FAILED_HOOK_NAME( void );
|
|
configUSE_MALLOC_FAILED_HOOK_NAME();
|
|
}
|
|
#elif 0
|
|
// If you want to alert debugger or halt...
|
|
while(1) { __asm("bkpt #0"); }; // Stop in GUI as if at a breakpoint (if debugging, otherwise loop forever)
|
|
#else
|
|
// If you prefer to believe your application will gracefully trap out-of-memory...
|
|
_impure_ptr->_errno = ENOMEM; // newlib's thread-specific errno
|
|
xTaskResumeAll();
|
|
#endif
|
|
return (char *)-1; // the malloc-family routine that called sbrk will return 0
|
|
}
|
|
currentHeapEnd += incr;
|
|
heapBytesRemaining -= incr;
|
|
#ifndef NDEBUG
|
|
totalBytesProvidedBySBRK += incr;
|
|
#endif
|
|
xTaskResumeAll();
|
|
return (char *) previousHeapEnd;
|
|
}
|
|
//! Synonym for sbrk.
|
|
char * _sbrk(int incr) { return sbrk(incr); };
|
|
|
|
void __malloc_lock(struct _reent *p) { vTaskSuspendAll(); };
|
|
void __malloc_unlock(struct _reent *p) { (void)xTaskResumeAll(); };
|
|
|
|
// newlib also requires implementing locks for the application's environment memory space,
|
|
// accessed by newlib's setenv() and getenv() functions.
|
|
// As these are trivial functions, momentarily suspend task switching (rather than semaphore).
|
|
// ToDo: Move __env_lock/unlock to a separate newlib helper file.
|
|
void __env_lock() { vTaskSuspendAll(); };
|
|
void __env_unlock() { (void)xTaskResumeAll(); };
|
|
|
|
/// /brief Wrap malloc/malloc_r to help debug who requests memory and why.
|
|
/// Add to the linker command line: -Xlinker --wrap=malloc -Xlinker --wrap=_malloc_r
|
|
// Note: These functions are normally unused and stripped by linker.
|
|
void *__wrap_malloc(size_t nbytes) {
|
|
extern void * __real_malloc(size_t nbytes);
|
|
void *p = __real_malloc(nbytes); // Solely for debug breakpoint...
|
|
return p;
|
|
};
|
|
void *__wrap__malloc_r(void *reent, size_t nbytes) {
|
|
extern void * __real__malloc_r(size_t nbytes);
|
|
void *p = __real__malloc_r(nbytes); // Solely for debug breakpoint...
|
|
return p;
|
|
};
|
|
|
|
|
|
// ================================================================================================
|
|
// Implement FreeRTOS's memory API using newlib-provided malloc family.
|
|
// ================================================================================================
|
|
|
|
void *pvPortMalloc( size_t xSize ) PRIVILEGED_FUNCTION {
|
|
void *p = malloc(xSize);
|
|
return p;
|
|
}
|
|
void vPortFree( void *pv ) PRIVILEGED_FUNCTION {
|
|
free(pv);
|
|
};
|
|
|
|
size_t xPortGetFreeHeapSize( void ) PRIVILEGED_FUNCTION {
|
|
struct mallinfo mi = mallinfo();
|
|
return mi.fordblks + heapBytesRemaining;
|
|
}
|
|
|
|
// GetMinimumEverFree is not available in newlib's malloc implementation.
|
|
// So, no implementation provided: size_t xPortGetMinimumEverFreeHeapSize( void ) PRIVILEGED_FUNCTION;
|
|
|
|
//! No implementation needed, but stub provided in case application already calls vPortInitialiseBlocks
|
|
void vPortInitialiseBlocks( void ) PRIVILEGED_FUNCTION {};
|
|
|
|
/*-----------------------------------------------------------*/
|
|
#if 1 /* << EST */
|
|
void vPortInitializeHeap(void) {
|
|
/* sorry, not able to free up the standard library heap */
|
|
}
|
|
#endif
|
|
|
|
#endif /* !defined(configUSE_HEAP_SCHEME) || (configUSE_HEAP_SCHEME==6) */
|
|
|