Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to 2-region model for HEAP and Stack Memory #9571

Merged
merged 40 commits into from Feb 27, 2019
Merged
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
a322327
Use 2-region memory model in ARM rtos-less builds.
mprse Jan 31, 2019
e60a0f4
Remove duplicated _mbed_user_setup_stackheap, __rt_lib_init definitions.
mprse Jan 31, 2019
9c11288
mbed_retarget.cpp: Fixed style
mprse Jan 31, 2019
26a6a9a
Add RAM memory model update document
Feb 1, 2019
a1fe750
Interrupt stack is always explicitly specified, hence other condition…
Feb 4, 2019
41eaefe
Update memory model for stack and heap memory
Feb 6, 2019
8b02a60
TARGET_ARM_FM: Set the heap size and limit
Feb 6, 2019
25bceda
TARGET_Atmel: Set the heap size and limit
Feb 6, 2019
5e4dcab
Target_Cypress: Set the heap limit
Feb 6, 2019
e03455a
Target_Freescale: Set the heap size and limit
Feb 6, 2019
25a127e
target_Gigadevice: Set the heap size and limit
Feb 6, 2019
8c63dbe
Target_Maxim: Setup heap limit and size
Feb 6, 2019
b2e189f
Target_Nuvoton: Remove target specific implementation of _sbrk
Feb 6, 2019
57b9ccc
Target_NXP: Setup heap limit and size
Feb 7, 2019
73f4a52
Target_ONSEMI: Setup heap limit and size
Feb 7, 2019
a814078
Target_UNO_91H: Remove custom _sbrk, update heap limits
Feb 7, 2019
c85ca4d
TARGET_RENESAS: _sbrk updated to use limits from linker files no need…
Feb 7, 2019
1f57568
TARGET_Silicon_Labs Setup heap limit and size
Feb 7, 2019
e522c46
Target_STM:_sbrk updated to use limits from linker files no need to s…
Feb 7, 2019
72ae546
TARGET_TOSHIBA :Setup heap limit and size
Feb 7, 2019
c6a72f2
TARGET_TT: Setup heap limit and size
Feb 7, 2019
462f339
TARGET_Wiznet: Setup heap limit and size
Feb 7, 2019
537b364
Resolve build/type cast errors
Feb 7, 2019
d0cc7ac
Target_Cypress: Update linker files to add heap limit
Feb 10, 2019
9ed7e4d
Remove unnecessary endif
Feb 10, 2019
9d1ce66
ISR_STACK_START/ HEAP_START defines not used by GCC_ARM toolchain
Feb 10, 2019
b36147f
ISR_Stack_start/size defines are not needed, use linker file defines
Feb 10, 2019
f13a3e3
Fix GCC _sbrk allocation
Feb 11, 2019
e7e9e07
Update K64F linker files for general solution of 2-ram regions
Feb 11, 2019
9231e26
Corrected main thread stack size, was accidently updated by removing …
Feb 12, 2019
2a1211a
Add heaplimit to NRF52 devices
Feb 12, 2019
1a1c74c
mbed_rtx.h not to include in platform
Feb 12, 2019
38e9314
Add missing space in linker script
Feb 12, 2019
60e7a7d
Add heap section to linker file
Feb 13, 2019
f518a69
Remove unused heap_size define
Feb 13, 2019
c5ad5f6
Target_Freescale:Add heap section
Feb 12, 2019
0d4d45e
Spell correction in design doc
Feb 18, 2019
dab2a30
Target_Freescale: Add heap section in linker files
Feb 20, 2019
387e4ca
New heap can be equal to heap limit for last chunk
Feb 21, 2019
49266c1
Remove TOOLCHAIN_GCC_CW_NEWLIB files
Feb 22, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
105 changes: 105 additions & 0 deletions docs/design-documents/platform/memory-model/ram_memory_model.md
@@ -0,0 +1,105 @@
# RAM memory model update - Mbed OS

# Table of contents

1. [RAM memory model update - Mbed OS](#mbed-os-ram-memory-model).
1. [Table of contents](#table-of-contents).
1. [Revision history](#revision-history).
1. [Introduction](#introduction).
1. [Current RAM memory model](#current-ram-memory-model).
1. [Proposed RAM memory model](#proposed-ram-memory-model).
1. [Phases](#phases).
1. Detailed Design (#detailed-design).
1. [Tools and configuration changes](#tools-and-configuration-changes).

### Revision history

1.0 - A brief description of this version. For example, Initial revision - Author name - Date.
**NOTE: You may also specify the Mbed OS version this revision of design document applies to.**
1.1 - Added new section - Author name - Date.

# Introduction

### Current RAM memory model

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.
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.

+----------------------+ Stack Start (Last address of RAM)
| ISR stack |
| Main Stack(No RTOS) |
| | |
| V |
+----------------------+
| ^ |
| | |
| Heap |
+----------------------+ HEAP Start
| ZI |
|(Idle, Timer and Main |
| stack is in ZI for |
| RTOS) |
+----------------------+
| |
+----------------------+ First address of RAM

#### Drawbacks:
1. Collisions between stack and heap are hard to detect and result in hardfault.
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.
1. Stack size unification cannot be achieved across various targets.
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
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.

### Proposed RAM memory model

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.

+----------------------+ Heap Ends (Last address of RAM)
| ^ |
| | |
| Heap |
+----------------------+ HEAP Start
| ZI |
|(Idle, Timer and Main |
| stack is in ZI for |
| RTOS) |
+----------------------+Stack Ends
| ISR stack |
| Main Stack(No RTOS) |
| | |
| V |
+----------------------+Stack Start
| |
+----------------------+ First address of RAM

#### Drawbacks:
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.

# Phases:
This feature will be implemented in different phases as follow:

Phase 1 (5.12 Release):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so what phase is being implemented in this PR ? is it Phase 1 only ?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes Phase 1 in this PR (5.12)

1. Adopt 2-region memory model for Stack and Heap memory.
1. Unify the stack size accross all targets (RTOS: ISR stack - 1K Main thread Stack - 4K; Bare Metal(No RTOS) ISR/Main Stack - 4K)

Phase 2:
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)
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.
1. ISR Stack to be placed after vectors or before ZI memory section.

Note: Heap split support across multiple RAM banks, can also be achieved post this change.

# Detailed Design
1. Update tools to set define `MBED_BOOT_STACK_SIZE` from target config option `target.boot-stack-size`
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.
1. Update __user_setup_stackheap() implementation to adopt 2-region RAM memory model.
__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.
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
1. Modify _sbrk() implementation for GCC to use 2-region memory model

# Tools and configuration changes

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.
Boot stack size - the size of ISR and main stack will be 4K as default in targets.json for bare metal (non-RTOS) builds.
Boot stack size - the size of ISR stack will be over-written as 1K in `rtos/mbed_lib.json` for RTOS builds.

76 changes: 37 additions & 39 deletions platform/mbed_retarget.cpp
Expand Up @@ -908,21 +908,44 @@ extern "C" long PREFIX(_flen)(FILEHANDLE fh)
// Do not compile this code for TFM secure target
#if !defined(COMPONENT_SPE) || !defined(TARGET_TFM)

extern "C" char Image$$RW_IRAM1$$ZI$$Limit[];
#if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
__asm(".global __use_two_region_memory\n\t");
__asm(".global __use_no_semihosting\n\t");

#else
#pragma import(__use_two_region_memory)
#endif

#if !defined(HEAP_START)
// Heap here is considered starting after ZI ends to Stack start
extern uint32_t Image$$ARM_LIB_STACK$$ZI$$Base[];
extern uint32_t Image$$RW_IRAM1$$ZI$$Limit[];
#define HEAP_START Image$$RW_IRAM1$$ZI$$Limit
#define HEAP_SIZE ((uint32_t)((uint32_t) Image$$ARM_LIB_STACK$$ZI$$Base - (uint32_t) HEAP_START))
#endif

#define HEAP_LIMIT ((uint32_t)((uint32_t)HEAP_START + (uint32_t)HEAP_SIZE))

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)
{
uint32_t zi_limit = (uint32_t)Image$$RW_IRAM1$$ZI$$Limit;
uint32_t sp_limit = __current_sp();
uint32_t heap_base = (uint32_t)HEAP_START;
struct __initial_stackheap r;

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

struct __initial_stackheap r;
r.heap_base = zi_limit;
r.heap_limit = sp_limit;
return r;
}

extern "C" __value_in_regs struct __argc_argv $Super$$__rt_lib_init(unsigned heapbase, unsigned heaptop);

extern "C" __value_in_regs struct __argc_argv $Sub$$__rt_lib_init(unsigned heapbase, unsigned heaptop)
{
return $Super$$__rt_lib_init((unsigned)HEAP_START, (unsigned)HEAP_LIMIT);
}

extern "C" __value_in_regs struct __initial_stackheap __user_setup_stackheap(uint32_t R0, uint32_t R1, uint32_t R2, uint32_t R3)
{
return _mbed_user_setup_stackheap(R0, R1, R2, R3);
Expand Down Expand Up @@ -1211,46 +1234,22 @@ extern "C" WEAK void __cxa_pure_virtual(void)
// SP. This make it compatible with RTX RTOS thread stacks.
#if defined(TOOLCHAIN_GCC_ARM)

#if defined(TARGET_CORTEX_A) || (defined(TARGET_TFM) && defined(COMPONENT_SPE))
extern "C" uint32_t __HeapLimit;
#endif
extern "C" uint32_t __end__;
extern "C" uint32_t __HeapLimit;

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

// Dynamic memory allocation related syscall.
#if defined(TWO_RAM_REGIONS)

// Overwrite _sbrk() to support two region model (heap and stack are two distinct regions).
// __wrap__sbrk() is implemented in:
// TARGET_STM32L4 targets/TARGET_STM/TARGET_STM32L4/TARGET_STM32L4/l4_retarget.c
extern "C" void *__wrap__sbrk(int incr);
extern "C" caddr_t _sbrk(int incr)
{
return (caddr_t) __wrap__sbrk(incr);
}
#else
// Linker defined symbol used by _sbrk to indicate where heap should start.
extern "C" uint32_t __end__;
// Weak attribute allows user to override, e.g. to use external RAM for dynamic memory.
extern "C" WEAK caddr_t _sbrk(int incr)
{
static unsigned char *heap = (unsigned char *)&__end__;
unsigned char *prev_heap = heap;
unsigned char *new_heap = heap + incr;

#if defined(TARGET_CORTEX_A) || (defined(TARGET_TFM) && defined(COMPONENT_SPE))
if (new_heap >= (unsigned char *)&__HeapLimit) { /* __HeapLimit is end of heap section */
#else
if (new_heap >= (unsigned char *)__get_MSP()) {
#endif
errno = ENOMEM;
return (caddr_t) -1;
}
static uint32_t heap = (uint32_t) &__end__;
uint32_t prev_heap = heap;
uint32_t new_heap = heap + incr;

// Additional heap checking if set
if (mbed_heap_size && (new_heap >= mbed_heap_start + mbed_heap_size)) {
/* __HeapLimit is end of heap section */
if (new_heap > (uint32_t) &__HeapLimit) {
errno = ENOMEM;
return (caddr_t) -1;
}
Expand All @@ -1259,7 +1258,6 @@ extern "C" WEAK caddr_t _sbrk(int incr)
return (caddr_t) prev_heap;
}
#endif
#endif

#if defined(TOOLCHAIN_GCC_ARM)
extern "C" void _exit(int return_code)
Expand Down
2 changes: 1 addition & 1 deletion platform/mbed_sdk_boot.c
Expand Up @@ -68,7 +68,7 @@ void mbed_copy_nvic(void)

/* Toolchain specific main code */

#if defined (__CC_ARM) || (defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 5010060))
#if defined (__ARMCC_VERSION)

int $Super$$main(void);

Expand Down
32 changes: 8 additions & 24 deletions rtos/TARGET_CORTEX/TOOLCHAIN_ARM_STD/mbed_boot_arm_std.c
Expand Up @@ -27,18 +27,14 @@
__value_in_regs struct __argc_argv __rt_lib_init(unsigned heapbase, unsigned heaptop);
void _platform_post_stackheap_init(void);

#if !defined(ISR_STACK_SIZE)
extern uint32_t Image$$ARM_LIB_STACK$$ZI$$Base[];
extern uint32_t Image$$ARM_LIB_STACK$$ZI$$Length[];
#define ISR_STACK_START ((unsigned char*)Image$$ARM_LIB_STACK$$ZI$$Base)
#define ISR_STACK_SIZE ((uint32_t)Image$$ARM_LIB_STACK$$ZI$$Length)
#endif

#if !defined(HEAP_START)
/* Defined by linker script */
extern uint32_t Image$$RW_IRAM1$$ZI$$Limit[];
#define HEAP_START ((unsigned char*)Image$$RW_IRAM1$$ZI$$Limit)
#define HEAP_SIZE ((uint32_t)((uint32_t)ISR_STACK_START - (uint32_t)HEAP_START))
// Heap here is considered starting after ZI ends to Stack start
extern uint32_t Image$$RW_IRAM1$$ZI$$Limit[];
#define HEAP_START Image$$RW_IRAM1$$ZI$$Limit
#define HEAP_SIZE ((uint32_t)((uint32_t)Image$$ARM_LIB_STACK$$ZI$$Base - (uint32_t)HEAP_START))
#endif

/*
Expand All @@ -58,23 +54,11 @@ extern uint32_t Image$$RW_IRAM1$$ZI$$Limit[];
*/
void __rt_entry(void)
{
unsigned char *free_start = HEAP_START;
uint32_t free_size = HEAP_SIZE;

#ifdef ISR_STACK_START
/* Interrupt stack explicitly specified */
mbed_stack_isr_size = ISR_STACK_SIZE;
mbed_stack_isr_start = ISR_STACK_START;
#else
/* Interrupt stack - reserve space at the end of the free block */
mbed_stack_isr_size = ISR_STACK_SIZE < free_size ? ISR_STACK_SIZE : free_size;
mbed_stack_isr_start = free_start + free_size - mbed_stack_isr_size;
free_size -= mbed_stack_isr_size;
#endif
mbed_stack_isr_start = (unsigned char *) Image$$ARM_LIB_STACK$$ZI$$Base;
mbed_stack_isr_size = (uint32_t) Image$$ARM_LIB_STACK$$ZI$$Length;
mbed_heap_start = (unsigned char *) HEAP_START;
mbed_heap_size = (uint32_t) HEAP_SIZE;

/* Heap - everything else */
mbed_heap_size = free_size;
mbed_heap_start = free_start;
mbed_init();

_platform_post_stackheap_init();
Expand Down
39 changes: 8 additions & 31 deletions rtos/TARGET_CORTEX/TOOLCHAIN_GCC_ARM/mbed_boot_gcc_arm.c
Expand Up @@ -29,19 +29,10 @@ static osMutexId_t env_mutex_id;
static mbed_rtos_storage_mutex_t env_mutex_obj;
static osMutexAttr_t env_mutex_attr;

#if !defined(ISR_STACK_SIZE)
extern uint32_t __StackLimit;
extern uint32_t __StackTop;
#define ISR_STACK_START ((unsigned char*)&__StackLimit)
#define ISR_STACK_SIZE ((uint32_t)((uint32_t)&__StackTop - (uint32_t)&__StackLimit))
#endif

#if !defined(HEAP_START)
/* Defined by linker script */
extern uint32_t __end__[];
#define HEAP_START ((unsigned char*)__end__)
#define HEAP_SIZE ((uint32_t)((uint32_t)ISR_STACK_START - (uint32_t)HEAP_START))
#endif
extern uint32_t __StackLimit;
extern uint32_t __StackTop;
extern uint32_t __end__;
extern uint32_t __HeapLimit;

extern void __libc_init_array(void);

Expand All @@ -52,24 +43,10 @@ extern void __libc_init_array(void);
*/
void software_init_hook(void)
{
unsigned char *free_start = HEAP_START;
uint32_t free_size = HEAP_SIZE;

#ifdef ISR_STACK_START
/* Interrupt stack explicitly specified */
mbed_stack_isr_size = ISR_STACK_SIZE;
mbed_stack_isr_start = ISR_STACK_START;
#else
/* Interrupt stack - reserve space at the end of the free block */
mbed_stack_isr_size = ISR_STACK_SIZE < free_size ? ISR_STACK_SIZE : free_size;
mbed_stack_isr_start = free_start + free_size - mbed_stack_isr_size;
free_size -= mbed_stack_isr_size;
#endif

/* Heap - everything else */
mbed_heap_size = free_size;
mbed_heap_start = free_start;

mbed_stack_isr_start = (unsigned char *) &__StackLimit;
mbed_stack_isr_size = (uint32_t) &__StackTop - (uint32_t) &__StackLimit;
mbed_heap_start = (unsigned char *) &__end__;
mbed_heap_size = (uint32_t) &__HeapLimit - (uint32_t) &__end__;

mbed_init();
mbed_rtos_start();
Expand Down
40 changes: 12 additions & 28 deletions rtos/TARGET_CORTEX/mbed_boot.c
Expand Up @@ -40,34 +40,18 @@
* Memory layout notes:
* ====================
*
* IAR Default Memory layout notes:
* -Heap defined by "HEAP" region in .icf file
* -Interrupt stack defined by "CSTACK" region in .icf file
* -Value INITIAL_SP is ignored
*
* IAR Custom Memory layout notes:
* -There is no custom layout available for IAR - everything must be defined in
* the .icf file and use the default layout
*
*
* GCC Default Memory layout notes:
* -Block of memory from symbol __end__ to define INITIAL_SP used to setup interrupt
* stack and heap in the function set_stack_heap()
* -ISR_STACK_SIZE can be overridden to be larger or smaller
*
* GCC Custom Memory layout notes:
* -Heap can be explicitly placed by defining both HEAP_START and HEAP_SIZE
* -Interrupt stack can be explicitly placed by defining both ISR_STACK_START and ISR_STACK_SIZE
*
*
* ARM Memory layout
* -Block of memory from end of region "RW_IRAM1" to define INITIAL_SP used to setup interrupt
* stack and heap in the function set_stack_heap()
* -ISR_STACK_SIZE can be overridden to be larger or smaller
*
* ARM Custom Memory layout notes:
* -Heap can be explicitly placed by defining both HEAP_START and HEAP_SIZE
* -Interrupt stack can be explicitly placed by defining both ISR_STACK_START and ISR_STACK_SIZE
* IAR Memory layout :
* - Heap defined by "HEAP" region in .icf file
* - Interrupt stack defined by "CSTACK" region in .icf file
* - Value INITIAL_SP is ignored
*
* GCC Memory layout :
* - Heap explicitly placed in linker script (*.ld file) and heap start (__end___) and heap end (__HeapLimit) should be defined in linker script
* - Interrupt stack placed in linker script **.ld file) and stack start (__StackTop) and stack end (__StackLimit) should be defined in linker script
*
* ARM Memory layout :
* - Heap can be explicitly placed by adding ARM_LIB_HEAP section in scatter file and defining both HEAP_START and HEAP_SIZE
* - Interrupt stack placed in scatter files (*.sct) by adding ARM_LIB_STACK section
*
*/

Expand Down
Expand Up @@ -202,6 +202,7 @@ SECTIONS
PROVIDE(end = .);
__HeapBase = .;
*(.heap*)
. = ORIGIN(RAM) + LENGTH(RAM) - STACK_SIZE;
__HeapLimit = .;
__heap_limit = .; /* Add for _sbrk */
} > RAM
Expand Down
Expand Up @@ -202,6 +202,7 @@ SECTIONS
PROVIDE(end = .);
__HeapBase = .;
*(.heap*)
. = ORIGIN(RAM) + LENGTH(RAM) - STACK_SIZE;
__HeapLimit = .;
__heap_limit = .; /* Add for _sbrk */
} > RAM
Expand Down