Skip to content

Commit e1736cd

Browse files
author
Cruz Monrreal
authored
Merge pull request #9571 from mprse/fix_9523_rtos_less_issue
Update to 2-region model for HEAP and Stack Memory
2 parents e77f03c + 49266c1 commit e1736cd

File tree

185 files changed

+428
-1193
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

185 files changed

+428
-1193
lines changed
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# RAM memory model update - Mbed OS
2+
3+
# Table of contents
4+
5+
1. [RAM memory model update - Mbed OS](#mbed-os-ram-memory-model).
6+
1. [Table of contents](#table-of-contents).
7+
1. [Revision history](#revision-history).
8+
1. [Introduction](#introduction).
9+
1. [Current RAM memory model](#current-ram-memory-model).
10+
1. [Proposed RAM memory model](#proposed-ram-memory-model).
11+
1. [Phases](#phases).
12+
1. Detailed Design (#detailed-design).
13+
1. [Tools and configuration changes](#tools-and-configuration-changes).
14+
15+
### Revision history
16+
17+
1.0 - A brief description of this version. For example, Initial revision - Author name - Date.
18+
**NOTE: You may also specify the Mbed OS version this revision of design document applies to.**
19+
1.1 - Added new section - Author name - Date.
20+
21+
# Introduction
22+
23+
### Current RAM memory model
24+
25+
Single memory space is shared between stack and heap memory, start address is fixed but the size of both regions varies based on application and usage runtime.
26+
Heap starts at the first address after the end of ZI growing up into higher memory address and stack starts at the last memory address of RAM growing downward into lower addresses.
27+
28+
+----------------------+ Stack Start (Last address of RAM)
29+
| ISR stack |
30+
| Main Stack(No RTOS) |
31+
| | |
32+
| V |
33+
+----------------------+
34+
| ^ |
35+
| | |
36+
| Heap |
37+
+----------------------+ HEAP Start
38+
| ZI |
39+
|(Idle, Timer and Main |
40+
| stack is in ZI for |
41+
| RTOS) |
42+
+----------------------+
43+
| |
44+
+----------------------+ First address of RAM
45+
46+
#### Drawbacks:
47+
1. Collisions between stack and heap are hard to detect and result in hardfault.
48+
1. Cannot check stack limit - In case of new ARM architecture stack limit registers are available to verify stack boundaries, but this feature cannot be used with dynamic stack size.
49+
1. Stack size unification cannot be achieved across various targets.
50+
1. GCC ARM: Memory allocator request memory at 4K boundary end of HEAP memory should be 4K aligned. Placing ISR stack (1K) after HEAP memory in case of RTOS, results in loss of 3K RAM memory
51+
1. Memory allocators do not support HEAP split into multiple banks, hence with single region memory model HEAP is used only till end of first bank.
52+
53+
### Proposed RAM memory model
54+
55+
2-region memory model for heap and stack. Defined boundaries for ISR stack memory. Heap memory can be dynamic (starts at end of ZI and ends at last RAM address) or with fix boundaries in separate RAM bank.
56+
57+
+----------------------+ Heap Ends (Last address of RAM)
58+
| ^ |
59+
| | |
60+
| Heap |
61+
+----------------------+ HEAP Start
62+
| ZI |
63+
|(Idle, Timer and Main |
64+
| stack is in ZI for |
65+
| RTOS) |
66+
+----------------------+Stack Ends
67+
| ISR stack |
68+
| Main Stack(No RTOS) |
69+
| | |
70+
| V |
71+
+----------------------+Stack Start
72+
| |
73+
+----------------------+ First address of RAM
74+
75+
#### Drawbacks:
76+
1. ISR Stack is not dynamic - This drawback is mainly for bare metal implementation (RTOS-less) where ISR and Main stack is same. With this limitation application writer should know if stack or heap will be usued more and tweaks the values accordingly.
77+
78+
# Phases:
79+
This feature will be implemented in different phases as follow:
80+
81+
Phase 1 (5.12 Release):
82+
1. Adopt 2-region memory model for Stack and Heap memory.
83+
1. Unify the stack size accross all targets (RTOS: ISR stack - 1K Main thread Stack - 4K; Bare Metal(No RTOS) ISR/Main Stack - 4K)
84+
85+
Phase 2:
86+
1. Heap memory to be dynamic and starts at the end of ZI growing up till end of RAM memory (In case of single RAM bank)
87+
Heap memory to be dynamic and assigned partial or full RAM bank in case of multiple RAM banks, based on calculation of other RAM regions.
88+
1. ISR Stack to be placed after vectors or before ZI memory section.
89+
90+
Note: Heap split support across multiple RAM banks, can also be achieved post this change.
91+
92+
# Detailed Design
93+
1. Update tools to set define `MBED_BOOT_STACK_SIZE` from target config option `target.boot-stack-size`
94+
1. Linker Scripts - Update linker scripts for ARM, IAR and GCC toolchain to use MBED_BOOT_STACK_SIZE define for standardizing size of ISR stack.
95+
1. Update __user_setup_stackheap() implementation to adopt 2-region RAM memory model.
96+
__user_setup_stackheap() works with systems where the application starts with a value of sp (r13) that is already correct. To make use of sp(stack base), implement __user_setup_stackheap() to set up r0 (heap base), r2 (heap limit), and r3 (stack limit) (for a two-region model) and return.
97+
Reference http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.kui0099a/armlib_cjagaaha.htm http://www.keil.com/support/man/docs/armlib/armlib_chr1359122863069.htm
98+
1. Modify _sbrk() implementation for GCC to use 2-region memory model
99+
100+
# Tools and configuration changes
101+
102+
1. Target config option "target.boot-stack-size" which is passed to the linker as the define "MBED_BOOT_STACK_SIZE" so the linker can adjust the stack accordingly.
103+
Boot stack size - the size of ISR and main stack will be 4K as default in targets.json for bare metal (non-RTOS) builds.
104+
Boot stack size - the size of ISR stack will be over-written as 1K in `rtos/mbed_lib.json` for RTOS builds.
105+

platform/mbed_retarget.cpp

Lines changed: 37 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -908,21 +908,44 @@ extern "C" long PREFIX(_flen)(FILEHANDLE fh)
908908
// Do not compile this code for TFM secure target
909909
#if !defined(COMPONENT_SPE) || !defined(TARGET_TFM)
910910

911-
extern "C" char Image$$RW_IRAM1$$ZI$$Limit[];
911+
#if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
912+
__asm(".global __use_two_region_memory\n\t");
913+
__asm(".global __use_no_semihosting\n\t");
914+
915+
#else
916+
#pragma import(__use_two_region_memory)
917+
#endif
918+
919+
#if !defined(HEAP_START)
920+
// Heap here is considered starting after ZI ends to Stack start
921+
extern uint32_t Image$$ARM_LIB_STACK$$ZI$$Base[];
922+
extern uint32_t Image$$RW_IRAM1$$ZI$$Limit[];
923+
#define HEAP_START Image$$RW_IRAM1$$ZI$$Limit
924+
#define HEAP_SIZE ((uint32_t)((uint32_t) Image$$ARM_LIB_STACK$$ZI$$Base - (uint32_t) HEAP_START))
925+
#endif
926+
927+
#define HEAP_LIMIT ((uint32_t)((uint32_t)HEAP_START + (uint32_t)HEAP_SIZE))
912928

913929
extern "C" MBED_WEAK __value_in_regs struct __initial_stackheap _mbed_user_setup_stackheap(uint32_t R0, uint32_t R1, uint32_t R2, uint32_t R3)
914930
{
915-
uint32_t zi_limit = (uint32_t)Image$$RW_IRAM1$$ZI$$Limit;
916-
uint32_t sp_limit = __current_sp();
931+
uint32_t heap_base = (uint32_t)HEAP_START;
932+
struct __initial_stackheap r;
917933

918-
zi_limit = (zi_limit + 7) & ~0x7; // ensure zi_limit is 8-byte aligned
934+
// Ensure heap_base is 8-byte aligned
935+
heap_base = (heap_base + 7) & ~0x7;
936+
r.heap_base = (uint32_t)heap_base;
937+
r.heap_limit = (uint32_t)HEAP_LIMIT;
919938

920-
struct __initial_stackheap r;
921-
r.heap_base = zi_limit;
922-
r.heap_limit = sp_limit;
923939
return r;
924940
}
925941

942+
extern "C" __value_in_regs struct __argc_argv $Super$$__rt_lib_init(unsigned heapbase, unsigned heaptop);
943+
944+
extern "C" __value_in_regs struct __argc_argv $Sub$$__rt_lib_init(unsigned heapbase, unsigned heaptop)
945+
{
946+
return $Super$$__rt_lib_init((unsigned)HEAP_START, (unsigned)HEAP_LIMIT);
947+
}
948+
926949
extern "C" __value_in_regs struct __initial_stackheap __user_setup_stackheap(uint32_t R0, uint32_t R1, uint32_t R2, uint32_t R3)
927950
{
928951
return _mbed_user_setup_stackheap(R0, R1, R2, R3);
@@ -1211,46 +1234,22 @@ extern "C" WEAK void __cxa_pure_virtual(void)
12111234
// SP. This make it compatible with RTX RTOS thread stacks.
12121235
#if defined(TOOLCHAIN_GCC_ARM)
12131236

1214-
#if defined(TARGET_CORTEX_A) || (defined(TARGET_TFM) && defined(COMPONENT_SPE))
1215-
extern "C" uint32_t __HeapLimit;
1216-
#endif
1237+
extern "C" uint32_t __end__;
1238+
extern "C" uint32_t __HeapLimit;
12171239

12181240
// Turn off the errno macro and use actual global variable instead.
12191241
#undef errno
12201242
extern "C" int errno;
12211243

1222-
// Dynamic memory allocation related syscall.
1223-
#if defined(TWO_RAM_REGIONS)
1224-
1225-
// Overwrite _sbrk() to support two region model (heap and stack are two distinct regions).
1226-
// __wrap__sbrk() is implemented in:
1227-
// TARGET_STM32L4 targets/TARGET_STM/TARGET_STM32L4/TARGET_STM32L4/l4_retarget.c
1228-
extern "C" void *__wrap__sbrk(int incr);
1229-
extern "C" caddr_t _sbrk(int incr)
1230-
{
1231-
return (caddr_t) __wrap__sbrk(incr);
1232-
}
1233-
#else
1234-
// Linker defined symbol used by _sbrk to indicate where heap should start.
1235-
extern "C" uint32_t __end__;
12361244
// Weak attribute allows user to override, e.g. to use external RAM for dynamic memory.
12371245
extern "C" WEAK caddr_t _sbrk(int incr)
12381246
{
1239-
static unsigned char *heap = (unsigned char *)&__end__;
1240-
unsigned char *prev_heap = heap;
1241-
unsigned char *new_heap = heap + incr;
1242-
1243-
#if defined(TARGET_CORTEX_A) || (defined(TARGET_TFM) && defined(COMPONENT_SPE))
1244-
if (new_heap >= (unsigned char *)&__HeapLimit) { /* __HeapLimit is end of heap section */
1245-
#else
1246-
if (new_heap >= (unsigned char *)__get_MSP()) {
1247-
#endif
1248-
errno = ENOMEM;
1249-
return (caddr_t) -1;
1250-
}
1247+
static uint32_t heap = (uint32_t) &__end__;
1248+
uint32_t prev_heap = heap;
1249+
uint32_t new_heap = heap + incr;
12511250

1252-
// Additional heap checking if set
1253-
if (mbed_heap_size && (new_heap >= mbed_heap_start + mbed_heap_size)) {
1251+
/* __HeapLimit is end of heap section */
1252+
if (new_heap > (uint32_t) &__HeapLimit) {
12541253
errno = ENOMEM;
12551254
return (caddr_t) -1;
12561255
}
@@ -1259,7 +1258,6 @@ extern "C" WEAK caddr_t _sbrk(int incr)
12591258
return (caddr_t) prev_heap;
12601259
}
12611260
#endif
1262-
#endif
12631261

12641262
#if defined(TOOLCHAIN_GCC_ARM)
12651263
extern "C" void _exit(int return_code)

platform/mbed_sdk_boot.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ void mbed_copy_nvic(void)
6868

6969
/* Toolchain specific main code */
7070

71-
#if defined (__CC_ARM) || (defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 5010060))
71+
#if defined (__ARMCC_VERSION)
7272

7373
int $Super$$main(void);
7474

rtos/TARGET_CORTEX/TOOLCHAIN_ARM_STD/mbed_boot_arm_std.c

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,14 @@
2727
__value_in_regs struct __argc_argv __rt_lib_init(unsigned heapbase, unsigned heaptop);
2828
void _platform_post_stackheap_init(void);
2929

30-
#if !defined(ISR_STACK_SIZE)
3130
extern uint32_t Image$$ARM_LIB_STACK$$ZI$$Base[];
3231
extern uint32_t Image$$ARM_LIB_STACK$$ZI$$Length[];
33-
#define ISR_STACK_START ((unsigned char*)Image$$ARM_LIB_STACK$$ZI$$Base)
34-
#define ISR_STACK_SIZE ((uint32_t)Image$$ARM_LIB_STACK$$ZI$$Length)
35-
#endif
3632

3733
#if !defined(HEAP_START)
38-
/* Defined by linker script */
39-
extern uint32_t Image$$RW_IRAM1$$ZI$$Limit[];
40-
#define HEAP_START ((unsigned char*)Image$$RW_IRAM1$$ZI$$Limit)
41-
#define HEAP_SIZE ((uint32_t)((uint32_t)ISR_STACK_START - (uint32_t)HEAP_START))
34+
// Heap here is considered starting after ZI ends to Stack start
35+
extern uint32_t Image$$RW_IRAM1$$ZI$$Limit[];
36+
#define HEAP_START Image$$RW_IRAM1$$ZI$$Limit
37+
#define HEAP_SIZE ((uint32_t)((uint32_t)Image$$ARM_LIB_STACK$$ZI$$Base - (uint32_t)HEAP_START))
4238
#endif
4339

4440
/*
@@ -58,23 +54,11 @@ extern uint32_t Image$$RW_IRAM1$$ZI$$Limit[];
5854
*/
5955
void __rt_entry(void)
6056
{
61-
unsigned char *free_start = HEAP_START;
62-
uint32_t free_size = HEAP_SIZE;
63-
64-
#ifdef ISR_STACK_START
65-
/* Interrupt stack explicitly specified */
66-
mbed_stack_isr_size = ISR_STACK_SIZE;
67-
mbed_stack_isr_start = ISR_STACK_START;
68-
#else
69-
/* Interrupt stack - reserve space at the end of the free block */
70-
mbed_stack_isr_size = ISR_STACK_SIZE < free_size ? ISR_STACK_SIZE : free_size;
71-
mbed_stack_isr_start = free_start + free_size - mbed_stack_isr_size;
72-
free_size -= mbed_stack_isr_size;
73-
#endif
57+
mbed_stack_isr_start = (unsigned char *) Image$$ARM_LIB_STACK$$ZI$$Base;
58+
mbed_stack_isr_size = (uint32_t) Image$$ARM_LIB_STACK$$ZI$$Length;
59+
mbed_heap_start = (unsigned char *) HEAP_START;
60+
mbed_heap_size = (uint32_t) HEAP_SIZE;
7461

75-
/* Heap - everything else */
76-
mbed_heap_size = free_size;
77-
mbed_heap_start = free_start;
7862
mbed_init();
7963

8064
_platform_post_stackheap_init();

rtos/TARGET_CORTEX/TOOLCHAIN_GCC_ARM/mbed_boot_gcc_arm.c

Lines changed: 8 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,10 @@ static osMutexId_t env_mutex_id;
2929
static mbed_rtos_storage_mutex_t env_mutex_obj;
3030
static osMutexAttr_t env_mutex_attr;
3131

32-
#if !defined(ISR_STACK_SIZE)
33-
extern uint32_t __StackLimit;
34-
extern uint32_t __StackTop;
35-
#define ISR_STACK_START ((unsigned char*)&__StackLimit)
36-
#define ISR_STACK_SIZE ((uint32_t)((uint32_t)&__StackTop - (uint32_t)&__StackLimit))
37-
#endif
38-
39-
#if !defined(HEAP_START)
40-
/* Defined by linker script */
41-
extern uint32_t __end__[];
42-
#define HEAP_START ((unsigned char*)__end__)
43-
#define HEAP_SIZE ((uint32_t)((uint32_t)ISR_STACK_START - (uint32_t)HEAP_START))
44-
#endif
32+
extern uint32_t __StackLimit;
33+
extern uint32_t __StackTop;
34+
extern uint32_t __end__;
35+
extern uint32_t __HeapLimit;
4536

4637
extern void __libc_init_array(void);
4738

@@ -52,24 +43,10 @@ extern void __libc_init_array(void);
5243
*/
5344
void software_init_hook(void)
5445
{
55-
unsigned char *free_start = HEAP_START;
56-
uint32_t free_size = HEAP_SIZE;
57-
58-
#ifdef ISR_STACK_START
59-
/* Interrupt stack explicitly specified */
60-
mbed_stack_isr_size = ISR_STACK_SIZE;
61-
mbed_stack_isr_start = ISR_STACK_START;
62-
#else
63-
/* Interrupt stack - reserve space at the end of the free block */
64-
mbed_stack_isr_size = ISR_STACK_SIZE < free_size ? ISR_STACK_SIZE : free_size;
65-
mbed_stack_isr_start = free_start + free_size - mbed_stack_isr_size;
66-
free_size -= mbed_stack_isr_size;
67-
#endif
68-
69-
/* Heap - everything else */
70-
mbed_heap_size = free_size;
71-
mbed_heap_start = free_start;
72-
46+
mbed_stack_isr_start = (unsigned char *) &__StackLimit;
47+
mbed_stack_isr_size = (uint32_t) &__StackTop - (uint32_t) &__StackLimit;
48+
mbed_heap_start = (unsigned char *) &__end__;
49+
mbed_heap_size = (uint32_t) &__HeapLimit - (uint32_t) &__end__;
7350

7451
mbed_init();
7552
mbed_rtos_start();

rtos/TARGET_CORTEX/mbed_boot.c

Lines changed: 12 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -40,34 +40,18 @@
4040
* Memory layout notes:
4141
* ====================
4242
*
43-
* IAR Default Memory layout notes:
44-
* -Heap defined by "HEAP" region in .icf file
45-
* -Interrupt stack defined by "CSTACK" region in .icf file
46-
* -Value INITIAL_SP is ignored
47-
*
48-
* IAR Custom Memory layout notes:
49-
* -There is no custom layout available for IAR - everything must be defined in
50-
* the .icf file and use the default layout
51-
*
52-
*
53-
* GCC Default Memory layout notes:
54-
* -Block of memory from symbol __end__ to define INITIAL_SP used to setup interrupt
55-
* stack and heap in the function set_stack_heap()
56-
* -ISR_STACK_SIZE can be overridden to be larger or smaller
57-
*
58-
* GCC Custom Memory layout notes:
59-
* -Heap can be explicitly placed by defining both HEAP_START and HEAP_SIZE
60-
* -Interrupt stack can be explicitly placed by defining both ISR_STACK_START and ISR_STACK_SIZE
61-
*
62-
*
63-
* ARM Memory layout
64-
* -Block of memory from end of region "RW_IRAM1" to define INITIAL_SP used to setup interrupt
65-
* stack and heap in the function set_stack_heap()
66-
* -ISR_STACK_SIZE can be overridden to be larger or smaller
67-
*
68-
* ARM Custom Memory layout notes:
69-
* -Heap can be explicitly placed by defining both HEAP_START and HEAP_SIZE
70-
* -Interrupt stack can be explicitly placed by defining both ISR_STACK_START and ISR_STACK_SIZE
43+
* IAR Memory layout :
44+
* - Heap defined by "HEAP" region in .icf file
45+
* - Interrupt stack defined by "CSTACK" region in .icf file
46+
* - Value INITIAL_SP is ignored
47+
*
48+
* GCC Memory layout :
49+
* - Heap explicitly placed in linker script (*.ld file) and heap start (__end___) and heap end (__HeapLimit) should be defined in linker script
50+
* - Interrupt stack placed in linker script **.ld file) and stack start (__StackTop) and stack end (__StackLimit) should be defined in linker script
51+
*
52+
* ARM Memory layout :
53+
* - Heap can be explicitly placed by adding ARM_LIB_HEAP section in scatter file and defining both HEAP_START and HEAP_SIZE
54+
* - Interrupt stack placed in scatter files (*.sct) by adding ARM_LIB_STACK section
7155
*
7256
*/
7357

targets/TARGET_ARM_FM/TARGET_FVP_MPS2/TARGET_FVP_MPS2_M0/device/TOOLCHAIN_GCC_ARM/MPS2.ld

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ SECTIONS
202202
PROVIDE(end = .);
203203
__HeapBase = .;
204204
*(.heap*)
205+
. = ORIGIN(RAM) + LENGTH(RAM) - STACK_SIZE;
205206
__HeapLimit = .;
206207
__heap_limit = .; /* Add for _sbrk */
207208
} > RAM

targets/TARGET_ARM_FM/TARGET_FVP_MPS2/TARGET_FVP_MPS2_M0P/device/TOOLCHAIN_GCC_ARM/MPS2.ld

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ SECTIONS
202202
PROVIDE(end = .);
203203
__HeapBase = .;
204204
*(.heap*)
205+
. = ORIGIN(RAM) + LENGTH(RAM) - STACK_SIZE;
205206
__HeapLimit = .;
206207
__heap_limit = .; /* Add for _sbrk */
207208
} > RAM

0 commit comments

Comments
 (0)