1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-18 12:52:44 +01:00

Merge pull request #12928 from benpicco/newlib-multiheap

sys/newlib: enable multiple heaps in _sbrk_r()
This commit is contained in:
Gunar Schorcht 2020-02-25 19:16:42 +01:00 committed by GitHub
commit f688f84a15
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 110 additions and 14 deletions

View File

@ -185,4 +185,9 @@ SECTIONS
/* Round size so that we can use 4 byte copy in init */ /* Round size so that we can use 4 byte copy in init */
. = ALIGN(4); . = ALIGN(4);
} > bkup-ram } > bkup-ram
.heap3 (NOLOAD) : ALIGN(4) {
_sheap1 = . ;
_eheap1 = ORIGIN(bkup-ram) + LENGTH(bkup-ram);
} > bkup-ram
} }

View File

@ -83,6 +83,12 @@ extern unsigned __stack_irq_size;
#define ISR_STACKSIZE ((unsigned) &__stack_irq_size) #define ISR_STACKSIZE ((unsigned) &__stack_irq_size)
/** @} */ /** @} */
/**
* @brief The CPU has 4 blocks of SRAM at different addresses.
* (primary RAM, USB RAM, Ethernet RAM & Backup RAM)
*/
#define NUM_HEAPS (4)
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -175,10 +175,10 @@ SECTIONS
_sram = ORIGIN(ram); _sram = ORIGIN(ram);
_eram = ORIGIN(ram) + LENGTH(ram); _eram = ORIGIN(ram) + LENGTH(ram);
__heap2_size = LENGTH(ram_ethernet); .heap1 ALIGN(4) (NOLOAD) :
.heap2 (NOLOAD) :
{ {
PROVIDE(__heap2_start = . ); _sheap1 = ORIGIN(ram_ethernet);
_eheap1 = ORIGIN(ram_ethernet) + LENGTH(ram_ethernet);
} > ram_ethernet } > ram_ethernet
. = ORIGIN(ram_usb); . = ORIGIN(ram_usb);
@ -187,12 +187,11 @@ SECTIONS
*(.usbdata) *(.usbdata)
} > ram_usb } > ram_usb
.heap3 ALIGN(0x1000) (NOLOAD) : .heap2 ALIGN(4) (NOLOAD) :
{ {
__heap3_size = ORIGIN(ram_usb) + LENGTH(ram_usb) - ABSOLUTE(.); _sheap2 = . ;
PROVIDE(__heap3_start = . ); _eheap2 = ORIGIN(ram_usb) + LENGTH(ram_usb);
} > ram_usb } > ram_usb
__heap_size = SIZEOF(.heap3);
_sbackup_data_load = LOADADDR(.backup.data); _sbackup_data_load = LOADADDR(.backup.data);
.backup.data : ALIGN(4) { .backup.data : ALIGN(4) {
@ -210,4 +209,9 @@ SECTIONS
/* Round size so that we can use 4 byte copy in init */ /* Round size so that we can use 4 byte copy in init */
. = ALIGN(4); . = ALIGN(4);
} > ram_battery } > ram_battery
.heap3 (NOLOAD) : ALIGN(4) {
_sheap3 = . ;
_eheap3 = ORIGIN(ram_battery) + LENGTH(ram_battery);
} > ram_battery
} }

View File

@ -126,6 +126,13 @@ as shown in the NVM Row Organization figure. */
#endif #endif
/** @} */ /** @} */
/**
* @brief The CPU has Low Power RAM that can be used as Heap
*/
#ifdef CPU_HAS_BACKUP_RAM
#define NUM_HEAPS (2)
#endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -56,12 +56,79 @@
#include "xtimer.h" #include "xtimer.h"
#endif #endif
#ifndef NUM_HEAPS
#define NUM_HEAPS 1
#endif
/** /**
* @brief manage the heap * @brief manage the heap
*/ */
extern char _sheap; /* start of the heap */ extern char _sheap; /* start of the heap */
extern char _eheap; /* end of the heap */ extern char _eheap; /* end of the heap */
char *heap_top = &_sheap + 4;
/**
* @brief Additional heap sections that may be defined in the linkerscript.
*
* The compiler should not generate references to those symbols if
* they are not used, so only provide them if additional memory sections
* that can be used as heap are available.
* @{
*/
extern char _sheap1;
extern char _eheap1;
extern char _sheap2;
extern char _eheap2;
extern char _sheap3;
extern char _eheap3;
/* @} */
struct heap {
char* start;
char* end;
};
static char *heap_top[NUM_HEAPS] = {
&_sheap,
#if NUM_HEAPS > 1
&_sheap1,
#endif
#if NUM_HEAPS > 2
&_sheap2,
#endif
#if NUM_HEAPS > 3
&_sheap3,
#endif
#if NUM_HEAPS > 4
#error "Unsupported NUM_HEAPS value, edit newlib_syscalls_default/syscalls.c to add more heaps."
#endif
};
static const struct heap heaps[NUM_HEAPS] = {
{
.start = &_sheap,
.end = &_eheap
},
#if NUM_HEAPS > 1
{
.start = &_sheap1,
.end = &_eheap1
},
#endif
#if NUM_HEAPS > 2
{
.start = &_sheap2,
.end = &_eheap2
},
#endif
#if NUM_HEAPS > 3
{
.start = &_sheap3,
.end = &_eheap3
},
#endif
};
/* MIPS newlib crt implements _init,_fini and _exit and manages the heap */ /* MIPS newlib crt implements _init,_fini and _exit and manages the heap */
#ifndef __mips__ #ifndef __mips__
@ -108,15 +175,22 @@ void _exit(int n)
*/ */
void *_sbrk_r(struct _reent *r, ptrdiff_t incr) void *_sbrk_r(struct _reent *r, ptrdiff_t incr)
{ {
void *res = (void*)UINTPTR_MAX;
unsigned int state = irq_disable(); unsigned int state = irq_disable();
void *res = heap_top;
if ((heap_top + incr > &_eheap) || (heap_top + incr < &_sheap)) { for (unsigned i = 0; i < NUM_HEAPS; ++i) {
r->_errno = ENOMEM; if ((heap_top[i] + incr > heaps[i].end) ||
res = (void *)-1; (heap_top[i] + incr < heaps[i].start)) {
continue;
}
res = heap_top[i];
heap_top[i] += incr;
break;
} }
else {
heap_top += incr; if (res == (void*)UINTPTR_MAX) {
r->_errno = ENOMEM;
} }
irq_restore(state); irq_restore(state);