Skip to content

Commit c10ff85

Browse files
committed
Added Dave Nadlers patch to nlib/freertos - via http://www.nadler.com/embedded/newlibAndFreeRTOS.html
1 parent 51a68e4 commit c10ff85

File tree

4 files changed

+372
-45
lines changed

4 files changed

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

STM32CubeIDE-TouchGFX-Fix/STM32CubeIDE-TouchGFX-Fix/Options.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,8 @@ public class Options
66
{
77
[Option('p', "path", Required = true, HelpText = "The folder path to your project (where your .cproject file is)")]
88
public string Path { get; set; }
9+
10+
[Option('n', "newlib", HelpText = "Set this flag to exclude automatic fix of newlib from the patch. Details here: http://www.nadler.com/embedded/newlibAndFreeRTOS.html")]
11+
public bool ExcludeNewLibFix { get; set; }
912
}
1013
}

0 commit comments

Comments
 (0)