Skip to content

Commit 1de0712

Browse files
authored
Merge pull request #9944 from deepikabhavnani/stm32_splitheap
GCC - Add support to split heap across 2-RAM banks
2 parents 8a92271 + 20a341d commit 1de0712

File tree

9 files changed

+333
-135
lines changed

9 files changed

+333
-135
lines changed

TESTS/mbedmicro-rtos-mbed/heap_and_stack/main.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ extern uint32_t mbed_heap_size;
4848
extern uint32_t mbed_stack_isr_start;
4949
extern uint32_t mbed_stack_isr_size;
5050

51+
#if defined(TOOLCHAIN_GCC_ARM) && defined(MBED_SPLIT_HEAP)
52+
extern uint32_t __mbed_sbrk_start_0;
53+
extern uint32_t __mbed_krbs_start_0;
54+
unsigned char *mbed_heap_start_0 = (unsigned char *) &__mbed_sbrk_start_0;;
55+
uint32_t mbed_heap_size_0 = (uint32_t) &__mbed_krbs_start_0 - (uint32_t) &__mbed_sbrk_start_0;
56+
#endif
5157

5258
struct linked_list {
5359
linked_list *next;
@@ -121,7 +127,11 @@ static void allocate_and_fill_heap(linked_list *&head)
121127
break;
122128
}
123129
bool result = rangeinrange((uint32_t) temp, sizeof(linked_list), mbed_heap_start, mbed_heap_size);
124-
130+
#if defined(TOOLCHAIN_GCC_ARM) && defined(MBED_SPLIT_HEAP)
131+
if (false == result) {
132+
result = rangeinrange((uint32_t) temp, sizeof(linked_list), (uint32_t)mbed_heap_start_0, mbed_heap_size_0);
133+
}
134+
#endif
125135
TEST_ASSERT_TRUE_MESSAGE(result, "Memory allocation out of range");
126136

127137
// Init
@@ -169,7 +179,11 @@ void test_heap_in_range(void)
169179
TEST_ASSERT_NOT_NULL(initial_heap);
170180

171181
bool result = inrange((uint32_t) initial_heap, mbed_heap_start, mbed_heap_size);
172-
182+
#if defined(TOOLCHAIN_GCC_ARM) && defined(MBED_SPLIT_HEAP)
183+
if (false == result) {
184+
result = inrange((uint32_t) initial_heap, (uint32_t)mbed_heap_start_0, mbed_heap_size_0);
185+
}
186+
#endif
173187
TEST_ASSERT_TRUE_MESSAGE(result, "Heap in wrong location");
174188
free(initial_heap);
175189
}

TESTS/mbedmicro-rtos-mbed/malloc/main.cpp

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,44 @@ void test_multithread_allocation(void)
107107
TEST_ASSERT_FALSE(thread_alloc_failure);
108108
}
109109

110+
/** Test for multiple heap alloc and free calls */
111+
#define ALLOC_ARRAY_SIZE 100
112+
#define ALLOC_LOOP 20
113+
#define SIZE_INCREMENTS 1023
114+
#define SIZE_MODULO 31
115+
116+
void test_alloc_and_free(void)
117+
{
118+
void *array[ALLOC_ARRAY_SIZE];
119+
void *data = NULL;
120+
long total_allocated = 0;
121+
int count = 0;
122+
int size = SIZE_INCREMENTS;
123+
int loop = ALLOC_LOOP;
124+
while (loop) {
125+
data = malloc(size);
126+
if (NULL != data) {
127+
array[count++] = data;
128+
memset((void *)data, 0xdeadbeef, size);
129+
total_allocated += size;
130+
size += SIZE_INCREMENTS;
131+
if (size > 10000) {
132+
size %= SIZE_MODULO;
133+
}
134+
} else {
135+
for (int i = 0; i < count; i++) {
136+
free(array[i]);
137+
array[i] = NULL;
138+
}
139+
loop--;
140+
printf("Total size dynamically allocated: %luB\n", total_allocated);
141+
total_allocated = 0;
142+
count = 0;
143+
continue;
144+
}
145+
}
146+
}
147+
110148
/** Test for large heap allocation
111149
112150
Given a heap of size mbed_heap_size
@@ -167,7 +205,8 @@ Case cases[] = {
167205
Case("Test 0 size allocation", test_zero_allocation),
168206
Case("Test NULL pointer free", test_null_free),
169207
Case("Test multithreaded allocations", test_multithread_allocation),
170-
Case("Test large allocation", test_big_allocation)
208+
Case("Test large allocation", test_big_allocation),
209+
Case("Test multiple alloc and free calls", test_alloc_and_free)
171210
};
172211

173212
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)

platform/mbed_retarget.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1258,6 +1258,46 @@ extern "C" WEAK void __cxa_pure_virtual(void)
12581258
// SP. This make it compatible with RTX RTOS thread stacks.
12591259
#if defined(TOOLCHAIN_GCC_ARM)
12601260

1261+
#if defined(MBED_SPLIT_HEAP)
1262+
1263+
// Default RAM memory used for heap
1264+
extern uint32_t __mbed_sbrk_start;
1265+
extern uint32_t __mbed_krbs_start;
1266+
/* Additional RAM memory used for heap - please note this
1267+
* address should be lower address then the previous default address
1268+
*/
1269+
extern uint32_t __mbed_sbrk_start_0;
1270+
extern uint32_t __mbed_krbs_start_0;
1271+
1272+
extern "C" WEAK caddr_t _sbrk(int incr)
1273+
{
1274+
static uint32_t heap = (uint32_t) &__mbed_sbrk_start_0;
1275+
static bool once = true;
1276+
uint32_t prev_heap = heap;
1277+
uint32_t new_heap = heap + incr;
1278+
1279+
/**
1280+
* If the new address is outside the first region, start allocating from the second region.
1281+
* Jump to second region is done just once, and `static bool once` is used to keep track of that.
1282+
*/
1283+
if (once && (new_heap > (uint32_t) &__mbed_krbs_start_0)) {
1284+
once = false;
1285+
prev_heap = (uint32_t) &__mbed_sbrk_start;
1286+
new_heap = prev_heap + incr;
1287+
} else if (new_heap > (uint32_t) &__mbed_krbs_start) {
1288+
/**
1289+
* If the new address is outside the second region, return out-of-memory.
1290+
*/
1291+
errno = ENOMEM;
1292+
return (caddr_t) - 1;
1293+
}
1294+
1295+
heap = new_heap;
1296+
return (caddr_t) prev_heap;
1297+
}
1298+
1299+
#else
1300+
12611301
extern "C" uint32_t __end__;
12621302
extern "C" uint32_t __HeapLimit;
12631303

@@ -1282,6 +1322,7 @@ extern "C" WEAK caddr_t _sbrk(int incr)
12821322
return (caddr_t) prev_heap;
12831323
}
12841324
#endif
1325+
#endif
12851326

12861327
#if defined(TOOLCHAIN_GCC_ARM)
12871328
extern "C" void _exit(int return_code)

targets/TARGET_STM/TARGET_STM32L4/TARGET_MTS_DRAGONFLY_L471QG/device/TOOLCHAIN_GCC_ARM/STM32L471XX.ld

Lines changed: 49 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ STACK_SIZE = MBED_BOOT_STACK_SIZE;
1414

1515
/* Linker script to configure memory regions. */
1616
MEMORY
17-
{
17+
{
1818
FLASH (rx) : ORIGIN = MBED_APP_START, LENGTH = MBED_APP_SIZE
1919
SRAM2 (rwx) : ORIGIN = 0x10000188, LENGTH = 32k - 0x188
2020
SRAM1 (rwx) : ORIGIN = 0x20000000, LENGTH = 96k
@@ -24,7 +24,7 @@ MEMORY
2424
* with other linker script that defines memory regions FLASH and RAM.
2525
* It references following symbols, which must be defined in code:
2626
* Reset_Handler : Entry of reset handler
27-
*
27+
*
2828
* It defines following symbols, which code can use without definition:
2929
* __exidx_start
3030
* __exidx_end
@@ -92,81 +92,100 @@ SECTIONS
9292
__etext = .;
9393
_sidata = .;
9494

95+
/* .stack section doesn't contains any symbols. It is only
96+
* used for linker to reserve space for the isr stack section
97+
* WARNING: .stack should come immediately after the last secure memory
98+
* section. This provides stack overflow detection. */
99+
.stack (NOLOAD):
100+
{
101+
__StackLimit = .;
102+
*(.stack*);
103+
. += STACK_SIZE - (. - __StackLimit);
104+
} > SRAM2
105+
106+
/* Set stack top to end of RAM, and stack limit move down by
107+
* size of stack_dummy section */
108+
__StackTop = ADDR(.stack) + SIZEOF(.stack);
109+
_estack = __StackTop;
110+
__StackLimit = ADDR(.stack);
111+
PROVIDE(__stack = __StackTop);
112+
113+
/* Place holder for additional heap */
114+
.heap_0 (COPY):
115+
{
116+
__mbed_sbrk_start_0 = .;
117+
. += (ORIGIN(SRAM2) + LENGTH(SRAM2) - .);
118+
__mbed_krbs_start_0 = .;
119+
} > SRAM2
120+
121+
/* Check if heap exceeds SRAM2 */
122+
ASSERT(__mbed_krbs_start_0 <= (ORIGIN(SRAM2)+LENGTH(SRAM2)), "Heap is too big for SRAM2")
123+
95124
.data : AT (__etext)
96125
{
97126
__data_start__ = .;
98127
_sdata = .;
99128
*(vtable)
100129
*(.data*)
101130

102-
. = ALIGN(4);
131+
. = ALIGN(8);
103132
/* preinit data */
104133
PROVIDE_HIDDEN (__preinit_array_start = .);
105134
KEEP(*(.preinit_array))
106135
PROVIDE_HIDDEN (__preinit_array_end = .);
107136

108-
. = ALIGN(4);
137+
. = ALIGN(8);
109138
/* init data */
110139
PROVIDE_HIDDEN (__init_array_start = .);
111140
KEEP(*(SORT(.init_array.*)))
112141
KEEP(*(.init_array))
113142
PROVIDE_HIDDEN (__init_array_end = .);
114143

115-
116-
. = ALIGN(4);
144+
. = ALIGN(8);
117145
/* finit data */
118146
PROVIDE_HIDDEN (__fini_array_start = .);
119147
KEEP(*(SORT(.fini_array.*)))
120148
KEEP(*(.fini_array))
121149
PROVIDE_HIDDEN (__fini_array_end = .);
122150

123151
KEEP(*(.jcr*))
124-
. = ALIGN(4);
152+
. = ALIGN(8);
125153
/* All data end */
126154
__data_end__ = .;
127155
_edata = .;
128156

129157
} > SRAM1
130158

159+
/* Check if bss exceeds SRAM1 */
160+
ASSERT(__data_end__ <= (ORIGIN(SRAM1)+LENGTH(SRAM1)), ".data is too big for SRAM1")
161+
131162
.bss :
132163
{
133-
. = ALIGN(4);
164+
. = ALIGN(8);
134165
__bss_start__ = .;
135166
_sbss = .;
136167
*(.bss*)
137168
*(COMMON)
138-
. = ALIGN(4);
169+
. = ALIGN(8);
139170
__bss_end__ = .;
140171
_ebss = .;
141172
} > SRAM1
142173

174+
/* Check if bss exceeds SRAM1 */
175+
ASSERT(__bss_end__ <= (ORIGIN(SRAM1)+LENGTH(SRAM1)), "BSS is too big for SRAM1")
176+
177+
/* Placeholder for default single heap */
143178
.heap (COPY):
144179
{
145180
__end__ = .;
146181
end = __end__;
182+
__mbed_sbrk_start = .;
147183
*(.heap*)
148184
. += (ORIGIN(SRAM1) + LENGTH(SRAM1) - .);
185+
__mbed_krbs_start = .;
149186
__HeapLimit = .;
150187
} > SRAM1
151-
PROVIDE(__heap_size = SIZEOF(.heap));
152-
PROVIDE(__mbed_sbrk_start = ADDR(.heap));
153-
PROVIDE(__mbed_krbs_start = ADDR(.heap) + SIZEOF(.heap));
154-
/* Check if data + heap exceeds RAM1 limit */
155-
ASSERT((ORIGIN(SRAM1)+LENGTH(SRAM1)) >= __HeapLimit, "SRAM1 overflow")
156-
/* .stack_dummy section doesn't contains any symbols. It is only
157-
* used for linker to calculate size of stack sections, and assign
158-
* values to stack symbols later */
159-
.stack_dummy (COPY):
160-
{
161-
*(.stack*)
162-
} > SRAM2
163188

164-
/* Set stack top to end of RAM, and stack limit move down by
165-
* size of stack_dummy section */
166-
__StackTop = ORIGIN(SRAM2) + LENGTH(SRAM2);
167-
_estack = __StackTop;
168-
__StackLimit = __StackTop - STACK_SIZE;
169-
PROVIDE(__stack = __StackTop);
170-
/* Check if stack exceeds RAM2 limit */
171-
ASSERT((ORIGIN(SRAM2)+LENGTH(SRAM2)) >= __StackLimit, "SRAM2 overflow")
172-
}
189+
/* Check if heap exceeds SRAM1 */
190+
ASSERT(__HeapLimit <= (ORIGIN(SRAM1)+LENGTH(SRAM1)), "Heap is too big for SRAM1")
191+
}

targets/TARGET_STM/TARGET_STM32L4/TARGET_STM32L443xC/device/TOOLCHAIN_GCC_ARM/STM32L443XX.ld

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,35 @@ SECTIONS
9393
__etext = .;
9494
_sidata = .;
9595

96+
/* .stack section doesn't contains any symbols. It is only
97+
* used for linker to reserve space for the isr stack section
98+
* WARNING: .stack should come immediately after the last secure memory
99+
* section. This provides stack overflow detection. */
100+
.stack (NOLOAD):
101+
{
102+
__StackLimit = .;
103+
*(.stack*);
104+
. += STACK_SIZE - (. - __StackLimit);
105+
} > SRAM2
106+
107+
/* Set stack top to end of RAM, and stack limit move down by
108+
* size of stack_dummy section */
109+
__StackTop = ADDR(.stack) + SIZEOF(.stack);
110+
_estack = __StackTop;
111+
__StackLimit = ADDR(.stack);
112+
PROVIDE(__stack = __StackTop);
113+
114+
/* Place holder for additional heap */
115+
.heap_0 (COPY):
116+
{
117+
__mbed_sbrk_start_0 = .;
118+
. += (ORIGIN(SRAM2) + LENGTH(SRAM2) - .);
119+
__mbed_krbs_start_0 = .;
120+
} > SRAM2
121+
122+
/* Check if heap exceeds SRAM2 */
123+
ASSERT(__mbed_krbs_start_0 <= (ORIGIN(SRAM2)+LENGTH(SRAM2)), "Heap is too big for SRAM2")
124+
96125
.data : AT (__etext)
97126
{
98127
__data_start__ = .;
@@ -129,6 +158,9 @@ SECTIONS
129158

130159
} > SRAM1
131160

161+
/* Check if bss exceeds SRAM1 */
162+
ASSERT(__data_end__ <= (ORIGIN(SRAM1)+LENGTH(SRAM1)), ".data is too big for SRAM1")
163+
132164
.bss :
133165
{
134166
. = ALIGN(8);
@@ -141,30 +173,21 @@ SECTIONS
141173
_ebss = .;
142174
} > SRAM1
143175

176+
/* Check if bss exceeds SRAM1 */
177+
ASSERT(__bss_end__ <= (ORIGIN(SRAM1)+LENGTH(SRAM1)), "BSS is too big for SRAM1")
178+
179+
/* Placeholder for default single heap */
144180
.heap (COPY):
145181
{
146182
__end__ = .;
147183
end = __end__;
184+
__mbed_sbrk_start = .;
148185
*(.heap*)
149-
. = ORIGIN(SRAM1) + LENGTH(SRAM1) - STACK_SIZE;
186+
. += (ORIGIN(SRAM1) + LENGTH(SRAM1) - .);
187+
__mbed_krbs_start = .;
150188
__HeapLimit = .;
151189
} > SRAM1
152190

153-
/* .stack_dummy section doesn't contains any symbols. It is only
154-
* used for linker to calculate size of stack sections, and assign
155-
* values to stack symbols later */
156-
.stack_dummy (COPY):
157-
{
158-
*(.stack*)
159-
} > SRAM1
160-
161-
/* Set stack top to end of RAM, and stack limit move down by
162-
* size of stack_dummy section */
163-
__StackTop = ORIGIN(SRAM1) + LENGTH(SRAM1);
164-
_estack = __StackTop;
165-
__StackLimit = __StackTop - STACK_SIZE;
166-
PROVIDE(__stack = __StackTop);
167-
168-
/* Check if data + heap + stack exceeds RAM limit */
169-
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack")
191+
/* Check if heap exceeds SRAM1 */
192+
ASSERT(__HeapLimit <= (ORIGIN(SRAM1)+LENGTH(SRAM1)), "Heap is too big for SRAM1")
170193
}

0 commit comments

Comments
 (0)