Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 4eca9f9

Browse filesBrowse files
committed
Add heap_useNewlib_ST.c from Dave Nadler to support newlib 3.1
https://nadler.com/embedded/newlibAndFreeRTOS.html https://github.com/DRNadler/FreeRTOS_helpers Signed-off-by: Frederic Pillon <frederic.pillon@st.com>
1 parent 53ea273 commit 4eca9f9
Copy full SHA for 4eca9f9

File tree

Expand file treeCollapse file tree

1 file changed

+284
-0
lines changed
Filter options
Expand file treeCollapse file tree

1 file changed

+284
-0
lines changed

‎portable/MemMang/heap_useNewlib_ST.c

Copy file name to clipboard
+284Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
/**
2+
* \file heap_useNewlib_ST.c
3+
* \brief Wrappers required to use newlib malloc-family within FreeRTOS.
4+
*
5+
* \par Overview
6+
* Route FreeRTOS memory management functions to newlib's malloc family.
7+
* Thus newlib and FreeRTOS share memory-management routines and memory pool,
8+
* and all newlib's internal memory-management requirements are supported.
9+
*
10+
* \author Dave Nadler
11+
* \date 20-August-2019
12+
* \version 27-Jun-2020 Correct "FreeRTOS.h" capitalization, commentary
13+
* \version 24-Jun-2020 commentary only
14+
* \version 11-Sep-2019 malloc accounting, comments, newlib version check
15+
*
16+
* \see http://www.nadler.com/embedded/newlibAndFreeRTOS.html
17+
* \see https://sourceware.org/newlib/libc.html#Reentrancy
18+
* \see https://sourceware.org/newlib/libc.html#malloc
19+
* \see https://sourceware.org/newlib/libc.html#index-_005f_005fenv_005flock
20+
* \see https://sourceware.org/newlib/libc.html#index-_005f_005fmalloc_005flock
21+
* \see https://sourceforge.net/p/freertos/feature-requests/72/
22+
* \see http://www.billgatliff.com/newlib.html
23+
* \see http://wiki.osdev.org/Porting_Newlib
24+
* \see http://www.embecosm.com/appnotes/ean9/ean9-howto-newlib-1.0.html
25+
*
26+
*
27+
* \copyright
28+
* (c) Dave Nadler 2017-2020, All Rights Reserved.
29+
* Web: http://www.nadler.com
30+
* email: drn@nadler.com
31+
*
32+
* Redistribution and use in source and binary forms, with or without modification,
33+
* are permitted provided that the following conditions are met:
34+
*
35+
* - Use or redistributions of source code must retain the above copyright notice,
36+
* this list of conditions, and the following disclaimer.
37+
*
38+
* - Use or redistributions of source code must retain ALL ORIGINAL COMMENTS, AND
39+
* ANY CHANGES MUST BE DOCUMENTED, INCLUDING:
40+
* - Reason for change (purpose)
41+
* - Functional change
42+
* - Date and author contact
43+
*
44+
* - Redistributions in binary form must reproduce the above copyright notice, this
45+
* list of conditions and the following disclaimer in the documentation and/or
46+
* other materials provided with the distribution.
47+
*
48+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
49+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
50+
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
51+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
52+
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
53+
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
54+
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
55+
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
56+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
57+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
58+
*/
59+
60+
// ================================================================================================
61+
// ======================================= Configuration ========================================
62+
// These configuration symbols could be provided by from build...
63+
#define STM_VERSION // Replace sane LD symbols with STM CubeMX's poor standard exported LD symbols
64+
#define ISR_STACK_LENGTH_BYTES (configISR_STACK_SIZE_WORDS*4) // bytes to reserve for ISR (MSP) stack
65+
// ======================================= Configuration ========================================
66+
// ================================================================================================
67+
68+
69+
#include <stdlib.h> // maps to newlib...
70+
#include <malloc.h> // mallinfo...
71+
#include <errno.h> // ENOMEM
72+
#include <stdbool.h>
73+
#include <stddef.h>
74+
75+
#include "newlib.h"
76+
#if ((__NEWLIB__ == 2) && (__NEWLIB_MINOR__ < 5)) ||((__NEWLIB__ == 3) && (__NEWLIB_MINOR__ > 1))
77+
#warning "This wrapper was verified for newlib versions 2.5 - 3.1; please ensure newlib's external requirements for malloc-family are unchanged!"
78+
#endif
79+
80+
#include "FreeRTOS.h" // defines public interface we're implementing here
81+
#if !defined(configUSE_NEWLIB_REENTRANT) || (configUSE_NEWLIB_REENTRANT!=1)
82+
#warning "#define configUSE_NEWLIB_REENTRANT 1 // Required for thread-safety of newlib sprintf, dtoa, strtok, etc..."
83+
// If you're *REALLY* sure you don't need FreeRTOS's newlib reentrancy support, comment out the above warning...
84+
#endif
85+
#include "task.h"
86+
87+
// ================================================================================================
88+
// External routines required by newlib's malloc (sbrk/_sbrk, __malloc_lock/unlock)
89+
// ================================================================================================
90+
91+
// Simplistic sbrk implementations assume stack grows downwards from top of memory,
92+
// and heap grows upwards starting just after BSS.
93+
// FreeRTOS normally allocates task stacks from a pool placed within BSS or DATA.
94+
// Thus within a FreeRTOS task, stack pointer is always below end of BSS.
95+
// When using this module, stacks are allocated from malloc pool, still always prior
96+
// current unused heap area...
97+
98+
// Doesn't work with FreeRTOS: STM CubeMX 2018-2019 Incorrect Implementation
99+
#if 0
100+
caddr_t _sbrk(int incr)
101+
{
102+
extern char end asm("end"); // From linker: lowest unused RAM address, just beyond end of BSS.
103+
static char *heap_end;
104+
char *prev_heap_end;
105+
if (heap_end == 0) heap_end = &end;
106+
prev_heap_end = heap_end;
107+
if (heap_end + incr > stack_ptr) // Fails here: always true for FreeRTOS task stacks
108+
{
109+
errno = ENOMEM; // ...so first call inside a FreeRTOS task lands here
110+
return (caddr_t) -1;
111+
}
112+
heap_end += incr;
113+
return (caddr_t) prev_heap_end;
114+
}
115+
#endif
116+
117+
register char * stack_ptr asm("sp");
118+
119+
#ifdef STM_VERSION // Use STM CubeMX LD symbols for heap+stack area
120+
// To avoid modifying STM LD file (and then having CubeMX trash it), use available STM symbols
121+
// Unfortunately STM does not provide standardized markers for RAM suitable for heap!
122+
// STM CubeMX-generated LD files provide the following symbols:
123+
// end /* aligned first word beyond BSS */
124+
// _estack /* one word beyond end of "RAM" Ram type memory, for STM32F429 0x20030000 */
125+
// Kludge below uses CubeMX-generated symbols instead of sane LD definitions
126+
#define __HeapBase end
127+
#define __HeapLimit _estack // In K64F LD this is already adjusted for ISR stack space...
128+
static int heapBytesRemaining;
129+
// no DRN HEAP_SIZE symbol from LD... // that's (&__HeapLimit)-(&__HeapBase)
130+
uint32_t TotalHeapSize; // publish for diagnostic routines; filled in first _sbrk call.
131+
#else
132+
// Note: DRN's K64F LD provided: __StackTop (byte beyond end of memory), __StackLimit, HEAP_SIZE, STACK_SIZE
133+
// __HeapLimit was already adjusted to be below reserved stack area.
134+
extern char HEAP_SIZE; // make sure to define this symbol in linker LD command file
135+
static int heapBytesRemaining = (int)&HEAP_SIZE; // that's (&__HeapLimit)-(&__HeapBase)
136+
#endif
137+
138+
139+
#ifdef MALLOCS_INSIDE_ISRs // STM code to avoid malloc within ISR (USB CDC stack)
140+
// We can't use vTaskSuspendAll() within an ISR.
141+
// STM's stunningly bad coding malpractice calls malloc within ISRs (for example, on USB connect function USBD_CDC_Init)
142+
// So, we must just suspend/resume interrupts, lengthening max interrupt response time, aarrggg...
143+
#define DRN_ENTER_CRITICAL_SECTION(_usis) { _usis = taskENTER_CRITICAL_FROM_ISR(); } // Disables interrupts (after saving prior state)
144+
#define DRN_EXIT_CRITICAL_SECTION(_usis) { taskEXIT_CRITICAL_FROM_ISR(_usis); } // Re-enables interrupts (unless already disabled prior taskENTER_CRITICAL)
145+
#else
146+
#define DRN_ENTER_CRITICAL_SECTION(_usis) vTaskSuspendAll(); // Note: safe to use before FreeRTOS scheduler started, but not in ISR
147+
#define DRN_EXIT_CRITICAL_SECTION(_usis) xTaskResumeAll(); // Note: safe to use before FreeRTOS scheduler started, but not in ISR
148+
#endif
149+
150+
#ifndef NDEBUG
151+
static int totalBytesProvidedBySBRK = 0;
152+
#endif
153+
extern char __HeapBase, __HeapLimit; // symbols from linker LD command file
154+
155+
// Use of vTaskSuspendAll() in _sbrk_r() is normally redundant, as newlib malloc family routines call
156+
// __malloc_lock before calling _sbrk_r(). Note vTaskSuspendAll/xTaskResumeAll support nesting.
157+
158+
//! _sbrk_r version supporting reentrant newlib (depends upon above symbols defined by linker control file).
159+
void * _sbrk_r(struct _reent *pReent, int incr) {
160+
#ifdef MALLOCS_INSIDE_ISRs // block interrupts during free-storage use
161+
UBaseType_t usis; // saved interrupt status
162+
#endif
163+
static char *currentHeapEnd = &__HeapBase;
164+
#ifdef STM_VERSION // Use STM CubeMX LD symbols for heap
165+
if(TotalHeapSize==0) {
166+
TotalHeapSize = heapBytesRemaining = (int)((&__HeapLimit)-(&__HeapBase))-ISR_STACK_LENGTH_BYTES;
167+
};
168+
#endif
169+
char* limit = (xTaskGetSchedulerState()==taskSCHEDULER_NOT_STARTED) ?
170+
stack_ptr : // Before scheduler is started, limit is stack pointer (risky!)
171+
&__HeapLimit-ISR_STACK_LENGTH_BYTES; // Once running, OK to reuse all remaining RAM except ISR stack (MSP) stack
172+
DRN_ENTER_CRITICAL_SECTION(usis);
173+
if (currentHeapEnd + incr > limit) {
174+
// Ooops, no more memory available...
175+
#if( configUSE_MALLOC_FAILED_HOOK == 1 )
176+
{
177+
extern void vApplicationMallocFailedHook( void );
178+
DRN_EXIT_CRITICAL_SECTION(usis);
179+
vApplicationMallocFailedHook();
180+
}
181+
#elif defined(configHARD_STOP_ON_MALLOC_FAILURE)
182+
// If you want to alert debugger or halt...
183+
// WARNING: brkpt instruction may prevent watchdog operation...
184+
while(1) { __asm("bkpt #0"); }; // Stop in GUI as if at a breakpoint (if debugging, otherwise loop forever)
185+
#else
186+
// Default, if you prefer to believe your application will gracefully trap out-of-memory...
187+
pReent->_errno = ENOMEM; // newlib's thread-specific errno
188+
DRN_EXIT_CRITICAL_SECTION(usis);
189+
#endif
190+
return (char *)-1; // the malloc-family routine that called sbrk will return 0
191+
}
192+
// 'incr' of memory is available: update accounting and return it.
193+
char *previousHeapEnd = currentHeapEnd;
194+
currentHeapEnd += incr;
195+
heapBytesRemaining -= incr;
196+
#ifndef NDEBUG
197+
totalBytesProvidedBySBRK += incr;
198+
#endif
199+
DRN_EXIT_CRITICAL_SECTION(usis);
200+
return (char *) previousHeapEnd;
201+
}
202+
//! non-reentrant sbrk uses is actually reentrant by using current context
203+
// ... because the current _reent structure is pointed to by global _impure_ptr
204+
char * sbrk(int incr) { return _sbrk_r(_impure_ptr, incr); }
205+
//! _sbrk is a synonym for sbrk.
206+
char * _sbrk(int incr) { return sbrk(incr); };
207+
208+
#ifdef MALLOCS_INSIDE_ISRs // block interrupts during free-storage use
209+
static UBaseType_t malLock_uxSavedInterruptStatus;
210+
#endif
211+
void __malloc_lock(struct _reent *r) {
212+
#if defined(MALLOCS_INSIDE_ISRs)
213+
DRN_ENTER_CRITICAL_SECTION(malLock_uxSavedInterruptStatus);
214+
#else
215+
bool insideAnISR = xPortIsInsideInterrupt();
216+
configASSERT( !insideAnISR ); // Make damn sure no more mallocs inside ISRs!!
217+
vTaskSuspendAll();
218+
#endif
219+
};
220+
void __malloc_unlock(struct _reent *r) {
221+
#if defined(MALLOCS_INSIDE_ISRs)
222+
DRN_EXIT_CRITICAL_SECTION(malLock_uxSavedInterruptStatus);
223+
#else
224+
(void)xTaskResumeAll();
225+
#endif
226+
};
227+
228+
// newlib also requires implementing locks for the application's environment memory space,
229+
// accessed by newlib's setenv() and getenv() functions.
230+
// As these are trivial functions, momentarily suspend task switching (rather than semaphore).
231+
// Not required (and trimmed by linker) in applications not using environment variables.
232+
// ToDo: Move __env_lock/unlock to a separate newlib helper file.
233+
void __env_lock() { vTaskSuspendAll(); };
234+
void __env_unlock() { (void)xTaskResumeAll(); };
235+
236+
#if 1 // Provide malloc debug and accounting wrappers
237+
/// /brief Wrap malloc/malloc_r to help debug who requests memory and why.
238+
/// To use these, add linker options: -Xlinker --wrap=malloc -Xlinker --wrap=_malloc_r
239+
// Note: These functions are normally unused and stripped by linker.
240+
size_t TotalMallocdBytes;
241+
int MallocCallCnt;
242+
static bool inside_malloc;
243+
void *__wrap_malloc(size_t nbytes) {
244+
extern void * __real_malloc(size_t nbytes);
245+
MallocCallCnt++;
246+
TotalMallocdBytes += nbytes;
247+
inside_malloc = true;
248+
void *p = __real_malloc(nbytes); // will call malloc_r...
249+
inside_malloc = false;
250+
return p;
251+
};
252+
void *__wrap__malloc_r(void *reent, size_t nbytes) {
253+
extern void * __real__malloc_r(size_t nbytes);
254+
if(!inside_malloc) {
255+
MallocCallCnt++;
256+
TotalMallocdBytes += nbytes;
257+
};
258+
void *p = __real__malloc_r(nbytes);
259+
return p;
260+
};
261+
#endif
262+
263+
// ================================================================================================
264+
// Implement FreeRTOS's memory API using newlib-provided malloc family.
265+
// ================================================================================================
266+
267+
void *pvPortMalloc( size_t xSize ) PRIVILEGED_FUNCTION {
268+
void *p = malloc(xSize);
269+
return p;
270+
}
271+
void vPortFree( void *pv ) PRIVILEGED_FUNCTION {
272+
free(pv);
273+
};
274+
275+
size_t xPortGetFreeHeapSize( void ) PRIVILEGED_FUNCTION {
276+
struct mallinfo mi = mallinfo(); // available space now managed by newlib
277+
return mi.fordblks + heapBytesRemaining; // plus space not yet handed to newlib by sbrk
278+
}
279+
280+
// GetMinimumEverFree is not available in newlib's malloc implementation.
281+
// So, no implementation is provided: size_t xPortGetMinimumEverFreeHeapSize( void ) PRIVILEGED_FUNCTION;
282+
283+
//! No implementation needed, but stub provided in case application already calls vPortInitialiseBlocks
284+
void vPortInitialiseBlocks( void ) PRIVILEGED_FUNCTION {};

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.