diff --git a/cpu/cortexm_common/ldscripts/cortexm_base.ld b/cpu/cortexm_common/ldscripts/cortexm_base.ld index f89e115fc8..2ed641a0f5 100644 --- a/cpu/cortexm_common/ldscripts/cortexm_base.ld +++ b/cpu/cortexm_common/ldscripts/cortexm_base.ld @@ -185,4 +185,9 @@ SECTIONS /* Round size so that we can use 4 byte copy in init */ . = ALIGN(4); } > bkup-ram + + .heap3 (NOLOAD) : ALIGN(4) { + _sheap1 = . ; + _eheap1 = ORIGIN(bkup-ram) + LENGTH(bkup-ram); + } > bkup-ram } diff --git a/cpu/lpc2387/include/cpu_conf.h b/cpu/lpc2387/include/cpu_conf.h index ad6699259d..1c72db1e7c 100644 --- a/cpu/lpc2387/include/cpu_conf.h +++ b/cpu/lpc2387/include/cpu_conf.h @@ -83,6 +83,12 @@ extern 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 } #endif diff --git a/cpu/lpc2387/ldscripts/lpc2387.ld b/cpu/lpc2387/ldscripts/lpc2387.ld index 8e266b5538..6619f571db 100644 --- a/cpu/lpc2387/ldscripts/lpc2387.ld +++ b/cpu/lpc2387/ldscripts/lpc2387.ld @@ -175,10 +175,10 @@ SECTIONS _sram = ORIGIN(ram); _eram = ORIGIN(ram) + LENGTH(ram); - __heap2_size = LENGTH(ram_ethernet); - .heap2 (NOLOAD) : + .heap1 ALIGN(4) (NOLOAD) : { - PROVIDE(__heap2_start = . ); + _sheap1 = ORIGIN(ram_ethernet); + _eheap1 = ORIGIN(ram_ethernet) + LENGTH(ram_ethernet); } > ram_ethernet . = ORIGIN(ram_usb); @@ -187,12 +187,11 @@ SECTIONS *(.usbdata) } > ram_usb - .heap3 ALIGN(0x1000) (NOLOAD) : + .heap2 ALIGN(4) (NOLOAD) : { - __heap3_size = ORIGIN(ram_usb) + LENGTH(ram_usb) - ABSOLUTE(.); - PROVIDE(__heap3_start = . ); + _sheap2 = . ; + _eheap2 = ORIGIN(ram_usb) + LENGTH(ram_usb); } > ram_usb - __heap_size = SIZEOF(.heap3); _sbackup_data_load = LOADADDR(.backup.data); .backup.data : ALIGN(4) { @@ -210,4 +209,9 @@ SECTIONS /* Round size so that we can use 4 byte copy in init */ . = ALIGN(4); } > ram_battery + + .heap3 (NOLOAD) : ALIGN(4) { + _sheap3 = . ; + _eheap3 = ORIGIN(ram_battery) + LENGTH(ram_battery); + } > ram_battery } diff --git a/cpu/sam0_common/include/cpu_conf.h b/cpu/sam0_common/include/cpu_conf.h index f1fc910149..d4500705bf 100644 --- a/cpu/sam0_common/include/cpu_conf.h +++ b/cpu/sam0_common/include/cpu_conf.h @@ -126,6 +126,13 @@ as shown in the NVM Row Organization figure. */ #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 } #endif diff --git a/sys/newlib_syscalls_default/syscalls.c b/sys/newlib_syscalls_default/syscalls.c index de58065520..e698fbb1e0 100644 --- a/sys/newlib_syscalls_default/syscalls.c +++ b/sys/newlib_syscalls_default/syscalls.c @@ -56,12 +56,79 @@ #include "xtimer.h" #endif +#ifndef NUM_HEAPS +#define NUM_HEAPS 1 +#endif + /** * @brief manage the heap */ extern char _sheap; /* start 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 */ #ifndef __mips__ @@ -108,15 +175,22 @@ void _exit(int n) */ void *_sbrk_r(struct _reent *r, ptrdiff_t incr) { + void *res = (void*)UINTPTR_MAX; unsigned int state = irq_disable(); - void *res = heap_top; - if ((heap_top + incr > &_eheap) || (heap_top + incr < &_sheap)) { - r->_errno = ENOMEM; - res = (void *)-1; + for (unsigned i = 0; i < NUM_HEAPS; ++i) { + if ((heap_top[i] + incr > heaps[i].end) || + (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);