Fix heap limit checking and make memory explicit

Set well defined limits for the heap and configure GCC and ARMCC to
correctly check these. IAR already correctly checked its heap.

This also statically declares the main thread stack so the
linker is responsible for its placement.
pull/2499/head
Russ Butler 2016-07-29 15:29:56 -05:00 committed by 0xc0170
parent 21903917c4
commit e913f49350
2 changed files with 146 additions and 60 deletions

View File

@ -68,6 +68,10 @@ extern const char __stdout_name[] = "/stdout";
extern const char __stderr_name[] = "/stderr"; extern const char __stderr_name[] = "/stderr";
#endif #endif
// Heap limits - only used if set
unsigned char *mbed_heap_start = 0;
uint32_t mbed_heap_size = 0;
/* newlib has the filehandle field in the FILE struct as a short, so /* newlib has the filehandle field in the FILE struct as a short, so
* we can't just return a Filehandle* from _open and instead have to * we can't just return a Filehandle* from _open and instead have to
* put it in a filehandles array and return the index into that array * put it in a filehandles array and return the index into that array
@ -596,6 +600,12 @@ extern "C" caddr_t _sbrk(int incr) {
return (caddr_t)-1; return (caddr_t)-1;
} }
// Additional heap checking if set
if (mbed_heap_size && (new_heap >= mbed_heap_start + mbed_heap_size)) {
errno = ENOMEM;
return (caddr_t)-1;
}
heap = new_heap; heap = new_heap;
return (caddr_t) prev_heap; return (caddr_t) prev_heap;
} }

194
rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h Executable file → Normal file
View File

@ -350,7 +350,41 @@ __attribute__((used)) void _mutex_release (OS_ID *mutex) {
/* Main Thread definition */ /* Main Thread definition */
extern void pre_main (void); extern void pre_main (void);
osThreadDef_t os_thread_def_main = {(os_pthread)pre_main, osPriorityNormal, 1U, 0U, NULL}; static uint32_t thread_stack_main[DEFAULT_STACK_SIZE * 2 / sizeof(uint32_t)];
osThreadDef_t os_thread_def_main = {(os_pthread)pre_main, osPriorityNormal, 1U, sizeof(thread_stack_main), thread_stack_main};
/*
* 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
*
*/
// This define should be probably moved to the CMSIS layer // This define should be probably moved to the CMSIS layer
#if defined(TARGET_LPC1768) #if defined(TARGET_LPC1768)
@ -534,19 +568,25 @@ extern uint32_t __StackTop[];
#elif defined(TARGET_NUMAKER_PFM_NUC472) #elif defined(TARGET_NUMAKER_PFM_NUC472)
# if defined(__CC_ARM) # if defined(__CC_ARM)
extern uint32_t Image$$ARM_LIB_STACK$$ZI$$Limit[]; extern uint32_t Image$$ARM_LIB_HEAP$$Base[];
extern uint32_t Image$$ARM_LIB_HEAP$$Length[];
extern uint32_t Image$$ARM_LIB_STACK$$ZI$$Base[]; extern uint32_t Image$$ARM_LIB_STACK$$ZI$$Base[];
#define INITIAL_SP ((uint32_t) Image$$ARM_LIB_STACK$$ZI$$Limit) extern uint32_t Image$$ARM_LIB_STACK$$ZI$$Length[];
#define FINAL_SP ((uint32_t) Image$$ARM_LIB_STACK$$ZI$$Base) #define HEAP_START ((unsigned char*) Image$$ARM_LIB_HEAP$$Base)
#define HEAP_SIZE ((uint32_t) Image$$ARM_LIB_HEAP$$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)
# elif defined(__GNUC__) # elif defined(__GNUC__)
extern uint32_t __StackTop[]; extern uint32_t __StackTop[];
extern uint32_t __StackLimit[]; extern uint32_t __StackLimit[];
#define INITIAL_SP ((uint32_t) __StackTop) extern uint32_t __end__[];
#define FINAL_SP ((uint32_t) __StackLimit) extern uint32_t __HeapLimit[];
#define HEAP_START ((unsigned char*)__end__)
#define HEAP_SIZE ((uint32_t)((uint32_t)__HeapLimit - (uint32_t)HEAP_START))
#define ISR_STACK_START ((unsigned char*)__StackLimit)
#define ISR_STACK_SIZE ((uint32_t)((uint32_t)__StackTop - (uint32_t)__StackLimit))
# elif defined(__ICCARM__) # elif defined(__ICCARM__)
#pragma section="CSTACK" /* No region declarations needed */
#define INITIAL_SP ((uint32_t) __section_end("CSTACK"))
#define FINAL_SP ((uint32_t) __section_begin("CSTACK"))
# else # else
#error "no toolchain defined" #error "no toolchain defined"
# endif # endif
@ -556,48 +596,90 @@ extern uint32_t __StackLimit[];
#endif #endif
#ifdef __CC_ARM extern unsigned char *mbed_heap_start;
#if defined(TARGET_NUMAKER_PFM_NUC472) extern uint32_t mbed_heap_size;
extern uint32_t Image$$ARM_LIB_HEAP$$Base[];
#define HEAP_START ((uint32_t) Image$$ARM_LIB_HEAP$$Base) unsigned char *mbed_stack_isr_start = 0;
#else uint32_t mbed_stack_isr_size = 0;
extern uint32_t Image$$RW_IRAM1$$ZI$$Limit[];
#define HEAP_START (Image$$RW_IRAM1$$ZI$$Limit) /*
* Sanity check values
*/
#if defined(__ICCARM__) && \
(defined(HEAP_START) || defined(HEAP_SIZE) || \
defined(ISR_STACK_START) && defined(ISR_STACK_SIZE))
#error "No custom layout allowed for IAR. Use .icf file instead"
#endif #endif
#elif defined(__GNUC__) #if defined(HEAP_START) && !defined(HEAP_SIZE)
extern uint32_t __end__[]; #error "HEAP_SIZE must be defined if HEAP_START is defined"
#define HEAP_START (__end__) #endif
#elif defined(__ICCARM__) #if defined(ISR_STACK_START) && !defined(ISR_STACK_SIZE)
#pragma section="HEAP" #error "ISR_STACK_SIZE must be defined if ISR_STACK_START is defined"
#define HEAP_END (void *)__section_end("HEAP") #endif
#if defined(HEAP_SIZE) && !defined(HEAP_START)
#error "HEAP_START must be defined if HEAP_SIZE is defined"
#endif #endif
void set_main_stack(void) { /* Interrupt stack and heap always defined for IAR
#if defined(TARGET_NUMAKER_PFM_NUC472) * Main thread defined here
// Scheduler stack: OS_MAINSTKSIZE words */
// Main thread stack: Reserved stack size - OS_MAINSTKSIZE words
os_thread_def_main.stack_pointer = (uint32_t *) FINAL_SP;
os_thread_def_main.stacksize = (uint32_t) INITIAL_SP - (uint32_t) FINAL_SP - OS_MAINSTKSIZE * 4;
#else
uint32_t interrupt_stack_size = ((uint32_t)OS_MAINSTKSIZE * 4);
#if defined(__ICCARM__) #if defined(__ICCARM__)
/* For IAR heap is defined .icf file */ #pragma section="CSTACK"
uint32_t main_stack_size = ((uint32_t)INITIAL_SP - (uint32_t)HEAP_END) - interrupt_stack_size; #pragma section="HEAP"
#define HEAP_START ((unsigned char*)__section_begin("HEAP"))
#define HEAP_SIZE ((uint32_t)__section_size("HEAP"))
#define ISR_STACK_START ((unsigned char*)__section_begin("CSTACK"))
#define ISR_STACK_SIZE ((uint32_t)__section_size("CSTACK"))
#endif
/* Define heap region if it has not been defined already */
#if !defined(HEAP_START)
#if defined(__ICCARM__)
#error "Heap should already be defined for IAR"
#elif defined(__CC_ARM)
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)INITIAL_SP - (uint32_t)HEAP_START))
#elif defined(__GNUC__)
extern uint32_t __end__[];
#define HEAP_START ((unsigned char*)__end__)
#define HEAP_SIZE ((uint32_t)((uint32_t)INITIAL_SP - (uint32_t)HEAP_START))
#endif
#endif
/* Define stack sizes if they haven't been set already */
#if !defined(ISR_STACK_SIZE)
#define ISR_STACK_SIZE ((uint32_t)OS_MAINSTKSIZE * 4)
#endif
/*
* set_stack_heap purpose is to set the following variables:
* -mbed_heap_start
* -mbed_heap_size
* -mbed_stack_isr_start
* -mbed_stack_isr_size
*
* Along with setting up os_thread_def_main
*/
void set_stack_heap(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 #else
/* For ARM , uARM, or GCC_ARM , heap can grow and reach main stack */ /* Interrupt stack - reserve space at the end of the free block */
uint32_t heap_plus_stack_size = ((uint32_t)INITIAL_SP - (uint32_t)HEAP_START) - interrupt_stack_size; mbed_stack_isr_size = ISR_STACK_SIZE;
// Main thread's stack is 1/4 of the heap mbed_stack_isr_start = free_start + free_size - mbed_stack_isr_size;
uint32_t main_stack_size = heap_plus_stack_size/4; free_size -= mbed_stack_isr_size;
#endif #endif
// The main thread must be 4 byte aligned
uint32_t main_stack_start = ((uint32_t)INITIAL_SP - interrupt_stack_size - main_stack_size) & ~0x7;
// That is the bottom of the main stack block: no collision detection /* Heap - everything else */
os_thread_def_main.stack_pointer = (uint32_t*)main_stack_start; mbed_heap_size = free_size;
mbed_heap_start = free_start;
// Leave OS_MAINSTKSIZE words for the scheduler and interrupts
os_thread_def_main.stacksize = main_stack_size;
#endif
} }
#if defined (__CC_ARM) #if defined (__CC_ARM)
@ -611,7 +693,7 @@ void $Super$$__cpp_initialize__aeabi_(void);
void _main_init (void) { void _main_init (void) {
osKernelInitialize(); osKernelInitialize();
#ifdef __MBED_CMSIS_RTOS_CM #ifdef __MBED_CMSIS_RTOS_CM
set_main_stack(); set_stack_heap();
#endif #endif
osThreadCreate(&os_thread_def_main, NULL); osThreadCreate(&os_thread_def_main, NULL);
osKernelStart(); osKernelStart();
@ -633,15 +715,12 @@ void pre_main()
#else #else
void * armcc_heap_base;
void * armcc_heap_top;
int main(void); int main(void);
void pre_main (void) void pre_main (void)
{ {
singleton_mutex_id = osMutexCreate(osMutex(singleton_mutex)); singleton_mutex_id = osMutexCreate(osMutex(singleton_mutex));
__rt_lib_init((unsigned)armcc_heap_base, (unsigned)armcc_heap_top); __rt_lib_init((unsigned)mbed_heap_start, (unsigned)(mbed_heap_start + mbed_heap_size));
main(); main();
} }
@ -656,12 +735,10 @@ void pre_main (void)
__asm void __rt_entry (void) { __asm void __rt_entry (void) {
IMPORT __user_setup_stackheap IMPORT __user_setup_stackheap
IMPORT armcc_heap_base
IMPORT armcc_heap_top
IMPORT os_thread_def_main IMPORT os_thread_def_main
IMPORT osKernelInitialize IMPORT osKernelInitialize
#ifdef __MBED_CMSIS_RTOS_CM #ifdef __MBED_CMSIS_RTOS_CM
IMPORT set_main_stack IMPORT set_stack_heap
#endif #endif
IMPORT osKernelStart IMPORT osKernelStart
IMPORT osThreadCreate IMPORT osThreadCreate
@ -675,13 +752,12 @@ __asm void __rt_entry (void) {
* ARM Compiler ARM C and C++ Libraries and Floating-Point Support User Guide * ARM Compiler ARM C and C++ Libraries and Floating-Point Support User Guide
*/ */
BL __user_setup_stackheap BL __user_setup_stackheap
LDR R3,=armcc_heap_base /* Ignore return value of __user_setup_stackheap since
LDR R4,=armcc_heap_top * this will be setup by set_stack_heap
STR R0,[R3] */
STR R2,[R4]
BL osKernelInitialize BL osKernelInitialize
#ifdef __MBED_CMSIS_RTOS_CM #ifdef __MBED_CMSIS_RTOS_CM
BL set_main_stack BL set_stack_heap
#endif #endif
LDR R0,=os_thread_def_main LDR R0,=os_thread_def_main
MOVS R1,#0 MOVS R1,#0
@ -719,7 +795,7 @@ __attribute__((naked)) void software_init_hook_rtos (void) {
__asm ( __asm (
"bl osKernelInitialize\n" "bl osKernelInitialize\n"
#ifdef __MBED_CMSIS_RTOS_CM #ifdef __MBED_CMSIS_RTOS_CM
"bl set_main_stack\n" "bl set_stack_heap\n"
#endif #endif
"ldr r0,=os_thread_def_main\n" "ldr r0,=os_thread_def_main\n"
"movs r1,#0\n" "movs r1,#0\n"
@ -796,7 +872,7 @@ void __iar_program_start( void )
#endif #endif
osKernelInitialize(); osKernelInitialize();
#ifdef __MBED_CMSIS_RTOS_CM #ifdef __MBED_CMSIS_RTOS_CM
set_main_stack(); set_stack_heap();
#endif #endif
osThreadCreate(&os_thread_def_main, NULL); osThreadCreate(&os_thread_def_main, NULL);
osKernelStart(); osKernelStart();