From 7cf1dc115516d3989b10dcde937aeee27ca96168 Mon Sep 17 00:00:00 2001 From: Russ Butler Date: Fri, 29 Jul 2016 15:29:56 -0500 Subject: [PATCH 1/9] 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. --- hal/common/retarget.cpp | 10 ++ rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h | 196 ++++++++++++++++++-------- 2 files changed, 146 insertions(+), 60 deletions(-) mode change 100755 => 100644 rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h diff --git a/hal/common/retarget.cpp b/hal/common/retarget.cpp index 4665b464d6..72d9a388c9 100644 --- a/hal/common/retarget.cpp +++ b/hal/common/retarget.cpp @@ -68,6 +68,10 @@ extern const char __stdout_name[] = "/stdout"; extern const char __stderr_name[] = "/stderr"; #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 * 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 @@ -596,6 +600,12 @@ extern "C" caddr_t _sbrk(int incr) { 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; return (caddr_t) prev_heap; } diff --git a/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h b/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h old mode 100755 new mode 100644 index dd69d10316..0cf15ae30f --- a/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h +++ b/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h @@ -350,7 +350,41 @@ __attribute__((used)) void _mutex_release (OS_ID *mutex) { /* Main Thread definition */ 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 #if defined(TARGET_LPC1768) @@ -534,19 +568,25 @@ extern uint32_t __StackTop[]; #elif defined(TARGET_NUMAKER_PFM_NUC472) # if defined(__CC_ARM) -extern uint32_t Image$$ARM_LIB_STACK$$ZI$$Limit[]; -extern uint32_t Image$$ARM_LIB_STACK$$ZI$$Base[]; -#define INITIAL_SP ((uint32_t) Image$$ARM_LIB_STACK$$ZI$$Limit) -#define FINAL_SP ((uint32_t) Image$$ARM_LIB_STACK$$ZI$$Base) +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$$Length[]; +#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__) extern uint32_t __StackTop[]; extern uint32_t __StackLimit[]; -#define INITIAL_SP ((uint32_t) __StackTop) -#define FINAL_SP ((uint32_t) __StackLimit) +extern uint32_t __end__[]; +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__) -#pragma section="CSTACK" -#define INITIAL_SP ((uint32_t) __section_end("CSTACK")) -#define FINAL_SP ((uint32_t) __section_begin("CSTACK")) +/* No region declarations needed */ # else #error "no toolchain defined" # endif @@ -556,48 +596,90 @@ extern uint32_t __StackLimit[]; #endif -#ifdef __CC_ARM -#if defined(TARGET_NUMAKER_PFM_NUC472) -extern uint32_t Image$$ARM_LIB_HEAP$$Base[]; -#define HEAP_START ((uint32_t) Image$$ARM_LIB_HEAP$$Base) -#else -extern uint32_t Image$$RW_IRAM1$$ZI$$Limit[]; -#define HEAP_START (Image$$RW_IRAM1$$ZI$$Limit) +extern unsigned char *mbed_heap_start; +extern uint32_t mbed_heap_size; + +unsigned char *mbed_stack_isr_start = 0; +uint32_t mbed_stack_isr_size = 0; + +/* + * 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 -#elif defined(__GNUC__) -extern uint32_t __end__[]; -#define HEAP_START (__end__) -#elif defined(__ICCARM__) -#pragma section="HEAP" -#define HEAP_END (void *)__section_end("HEAP") +#if defined(HEAP_START) && !defined(HEAP_SIZE) + #error "HEAP_SIZE must be defined if HEAP_START is defined" +#endif +#if defined(ISR_STACK_START) && !defined(ISR_STACK_SIZE) + #error "ISR_STACK_SIZE must be defined if ISR_STACK_START is defined" +#endif +#if defined(HEAP_SIZE) && !defined(HEAP_START) + #error "HEAP_START must be defined if HEAP_SIZE is defined" #endif -void set_main_stack(void) { -#if defined(TARGET_NUMAKER_PFM_NUC472) - // 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); +/* Interrupt stack and heap always defined for IAR + * Main thread defined here + */ #if defined(__ICCARM__) - /* For IAR heap is defined .icf file */ - uint32_t main_stack_size = ((uint32_t)INITIAL_SP - (uint32_t)HEAP_END) - interrupt_stack_size; + #pragma section="CSTACK" + #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 - /* For ARM , uARM, or GCC_ARM , heap can grow and reach main stack */ - uint32_t heap_plus_stack_size = ((uint32_t)INITIAL_SP - (uint32_t)HEAP_START) - interrupt_stack_size; - // Main thread's stack is 1/4 of the heap - uint32_t main_stack_size = heap_plus_stack_size/4; + /* Interrupt stack - reserve space at the end of the free block */ + mbed_stack_isr_size = ISR_STACK_SIZE; + mbed_stack_isr_start = free_start + free_size - mbed_stack_isr_size; + free_size -= mbed_stack_isr_size; #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 - os_thread_def_main.stack_pointer = (uint32_t*)main_stack_start; - - // Leave OS_MAINSTKSIZE words for the scheduler and interrupts - os_thread_def_main.stacksize = main_stack_size; -#endif + /* Heap - everything else */ + mbed_heap_size = free_size; + mbed_heap_start = free_start; } #if defined (__CC_ARM) @@ -611,7 +693,7 @@ void $Super$$__cpp_initialize__aeabi_(void); void _main_init (void) { osKernelInitialize(); #ifdef __MBED_CMSIS_RTOS_CM - set_main_stack(); + set_stack_heap(); #endif osThreadCreate(&os_thread_def_main, NULL); osKernelStart(); @@ -633,15 +715,12 @@ void pre_main() #else -void * armcc_heap_base; -void * armcc_heap_top; - int main(void); void pre_main (void) { 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(); } @@ -656,12 +735,10 @@ void pre_main (void) __asm void __rt_entry (void) { IMPORT __user_setup_stackheap - IMPORT armcc_heap_base - IMPORT armcc_heap_top IMPORT os_thread_def_main IMPORT osKernelInitialize #ifdef __MBED_CMSIS_RTOS_CM - IMPORT set_main_stack + IMPORT set_stack_heap #endif IMPORT osKernelStart IMPORT osThreadCreate @@ -675,13 +752,12 @@ __asm void __rt_entry (void) { * ARM Compiler ARM C and C++ Libraries and Floating-Point Support User Guide */ BL __user_setup_stackheap - LDR R3,=armcc_heap_base - LDR R4,=armcc_heap_top - STR R0,[R3] - STR R2,[R4] + /* Ignore return value of __user_setup_stackheap since + * this will be setup by set_stack_heap + */ BL osKernelInitialize #ifdef __MBED_CMSIS_RTOS_CM - BL set_main_stack + BL set_stack_heap #endif LDR R0,=os_thread_def_main MOVS R1,#0 @@ -719,7 +795,7 @@ __attribute__((naked)) void software_init_hook_rtos (void) { __asm ( "bl osKernelInitialize\n" #ifdef __MBED_CMSIS_RTOS_CM - "bl set_main_stack\n" + "bl set_stack_heap\n" #endif "ldr r0,=os_thread_def_main\n" "movs r1,#0\n" @@ -796,7 +872,7 @@ void __iar_program_start( void ) #endif osKernelInitialize(); #ifdef __MBED_CMSIS_RTOS_CM - set_main_stack(); + set_stack_heap(); #endif osThreadCreate(&os_thread_def_main, NULL); osKernelStart(); From da4787f036444b9de8496f745a46c9ad91fdc31f Mon Sep 17 00:00:00 2001 From: Russ Butler Date: Wed, 3 Aug 2016 14:28:53 -0500 Subject: [PATCH 2/9] Adjust stack size for the nrf51 Decrease the main stack size for the nrf51 so there is more heap space available. --- rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h b/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h index 0cf15ae30f..d5a88bef60 100644 --- a/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h +++ b/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h @@ -350,7 +350,12 @@ __attribute__((used)) void _mutex_release (OS_ID *mutex) { /* Main Thread definition */ extern void pre_main (void); + +#if defined(TARGET_MCU_NRF51822) || defined(TARGET_MCU_NRF52832) +static uint32_t thread_stack_main[DEFAULT_STACK_SIZE / sizeof(uint32_t)]; +#else static uint32_t thread_stack_main[DEFAULT_STACK_SIZE * 2 / sizeof(uint32_t)]; +#endif osThreadDef_t os_thread_def_main = {(os_pthread)pre_main, osPriorityNormal, 1U, sizeof(thread_stack_main), thread_stack_main}; /* From 16329fd2d93f58728ac10e317db9d88ac7b153d1 Mon Sep 17 00:00:00 2001 From: Russ Butler Date: Mon, 1 Aug 2016 09:07:35 -0500 Subject: [PATCH 3/9] Override new and delete operators to trap errors When new or new[] fails to allocate space trigger an error. --- hal/common/retarget.cpp | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/hal/common/retarget.cpp b/hal/common/retarget.cpp index 72d9a388c9..a09854fec5 100644 --- a/hal/common/retarget.cpp +++ b/hal/common/retarget.cpp @@ -23,6 +23,8 @@ #include "mbed_interface.h" #include "SingletonPtr.h" #include "PlatformMutex.h" +#include "mbed_error.h" +#include #if DEVICE_STDIO_MESSAGES #include #endif @@ -724,3 +726,34 @@ extern "C" void __env_unlock( struct _reent *_r ) #endif } // namespace mbed + +void *operator new(std::size_t count) +{ + void *buffer = malloc(count); + if (NULL == buffer) { + error("Operator new out of memory\r\n"); + } + return buffer; +} + +void *operator new[](std::size_t count) +{ + void *buffer = malloc(count); + if (NULL == buffer) { + error("Operator new[] out of memory\r\n"); + } + return buffer; +} + +void operator delete(void *ptr) +{ + if (ptr != NULL) { + free(ptr); + } +} +void operator delete[](void *ptr) +{ + if (ptr != NULL) { + free(ptr); + } +} From 1d3d01f0000079ccf32a36cd3eada3cc2dd09ade Mon Sep 17 00:00:00 2001 From: Russ Butler Date: Wed, 3 Aug 2016 14:31:45 -0500 Subject: [PATCH 4/9] Correctly set INITIAL_SP for K64F With the latest K64F linker file the initial stack is out of sync with INITIAL_SP when uVisor is not present. This patch removes the incorrect declaration. --- rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h b/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h index d5a88bef60..241d3153e8 100644 --- a/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h +++ b/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h @@ -420,7 +420,7 @@ osThreadDef_t os_thread_def_main = {(os_pthread)pre_main, osPriorityNormal, 1U, #define INITIAL_SP (0x20003000UL) #elif defined(TARGET_K64F) -#if defined(FEATURE_UVISOR) && defined(TARGET_UVISOR_SUPPORTED) +#if defined(__GNUC__) && !defined(__CC_ARM) /* GCC */ extern uint32_t __StackTop[]; #define INITIAL_SP (__StackTop) #else From 81382ebdb2332b1032cbe6b11b3a89bbbbf93214 Mon Sep 17 00:00:00 2001 From: Russ Butler Date: Fri, 29 Jul 2016 16:03:29 -0500 Subject: [PATCH 5/9] Turn on main thread stack checking Since the heap and stack are no longer shared, stack checking on the main thread can be turned back on. This allows stack overflows on the main thread to be caught quickly. --- rtos/rtx/TARGET_CORTEX_M/HAL_CM.c | 27 --------------------------- rtos/rtx/TARGET_CORTEX_M/cmsis_os.h | 8 -------- rtos/rtx/TARGET_CORTEX_M/rt_System.c | 12 ------------ 3 files changed, 47 deletions(-) diff --git a/rtos/rtx/TARGET_CORTEX_M/HAL_CM.c b/rtos/rtx/TARGET_CORTEX_M/HAL_CM.c index 76c2d9d141..d423085e3d 100644 --- a/rtos/rtx/TARGET_CORTEX_M/HAL_CM.c +++ b/rtos/rtx/TARGET_CORTEX_M/HAL_CM.c @@ -90,32 +90,6 @@ void rt_init_stack (P_TCB p_TCB, FUNCP task_body) { /* Task entry point. */ p_TCB->ptask = task_body; - -#ifdef __MBED_CMSIS_RTOS_CM - /* Set a magic word for checking of stack overflow. - For the main thread (ID: MAIN_THREAD_ID) the stack is in a memory area shared with the - heap, therefore the last word of the stack is a moving target. - We want to do stack/heap collision detection instead. - Similar applies to stack filling for the magic pattern. - */ - if (p_TCB->task_id != MAIN_THREAD_ID) { - p_TCB->stack[0] = MAGIC_WORD; - - /* Initialize stack with magic pattern. */ - if (os_stackinfo & 0x10000000U) { - if (size > (16U+1U)) { - for (i = ((size - 16U)/2U) - 1U; i; i--) { - stk -= 2U; - stk[1] = MAGIC_PATTERN; - stk[0] = MAGIC_PATTERN; - } - if (--stk > p_TCB->stack) { - *stk = MAGIC_PATTERN; - } - } - } - } -#else /* Initialize stack with magic pattern. */ if (os_stackinfo & 0x10000000U) { if (size > (16U+1U)) { @@ -132,7 +106,6 @@ void rt_init_stack (P_TCB p_TCB, FUNCP task_body) { /* Set a magic word for checking of stack overflow. */ p_TCB->stack[0] = MAGIC_WORD; -#endif } diff --git a/rtos/rtx/TARGET_CORTEX_M/cmsis_os.h b/rtos/rtx/TARGET_CORTEX_M/cmsis_os.h index 1f3b799cfb..ac052ff82b 100644 --- a/rtos/rtx/TARGET_CORTEX_M/cmsis_os.h +++ b/rtos/rtx/TARGET_CORTEX_M/cmsis_os.h @@ -80,14 +80,6 @@ #define OS_TIMERS 0 #endif -/* If os timers macro is set to 0, there's no timer thread created, therefore - * main thread has tid 0x01 - */ -#if defined(OS_TIMERS) && (OS_TIMERS == 0) -#define MAIN_THREAD_ID 0x01 -#else -#define MAIN_THREAD_ID 0x02 -#endif #endif #define DEFAULT_STACK_SIZE (WORDS_STACK_SIZE*4) diff --git a/rtos/rtx/TARGET_CORTEX_M/rt_System.c b/rtos/rtx/TARGET_CORTEX_M/rt_System.c index 4d687d4fa4..a04e6890f2 100644 --- a/rtos/rtx/TARGET_CORTEX_M/rt_System.c +++ b/rtos/rtx/TARGET_CORTEX_M/rt_System.c @@ -313,22 +313,10 @@ void rt_systick (void) { /*--------------------------- rt_stk_check ----------------------------------*/ __weak void rt_stk_check (void) { -#ifdef __MBED_CMSIS_RTOS_CM - /* Check for stack overflow. */ - if (os_tsk.run->task_id == MAIN_THREAD_ID) { - // TODO: For the main thread the check should be done against the main heap pointer - } else { - if ((os_tsk.run->tsk_stack < (U32)os_tsk.run->stack) || - (os_tsk.run->stack[0] != MAGIC_WORD)) { - os_error (OS_ERR_STK_OVF); - } - } -#else if ((os_tsk.run->tsk_stack < (U32)os_tsk.run->stack) || (os_tsk.run->stack[0] != MAGIC_WORD)) { os_error (OS_ERR_STK_OVF); } -#endif } /*---------------------------------------------------------------------------- From 1615dca6bd642a18940400634f99d7756b25baa6 Mon Sep 17 00:00:00 2001 From: Russ Butler Date: Fri, 29 Jul 2016 15:34:23 -0500 Subject: [PATCH 6/9] Add a test for heap and stack layout Test the following components of the heap and stacks: -Heap and interrupt stack are at the expected locations -Entire heap can be used -Heap limit is properly enforced and returns NULL when out of of memory --- .../TESTS/memory/heap_and_stack/main.cpp | 179 ++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 rtos/rtx/TARGET_CORTEX_M/TESTS/memory/heap_and_stack/main.cpp diff --git a/rtos/rtx/TARGET_CORTEX_M/TESTS/memory/heap_and_stack/main.cpp b/rtos/rtx/TARGET_CORTEX_M/TESTS/memory/heap_and_stack/main.cpp new file mode 100644 index 0000000000..7e273504d1 --- /dev/null +++ b/rtos/rtx/TARGET_CORTEX_M/TESTS/memory/heap_and_stack/main.cpp @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2016-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include "greentea-client/test_env.h" +#include "cmsis.h" +#include "mbed.h" +#include "rtos.h" +#include "mbed_assert.h" + +// Amount to malloc for each iteration +#define MALLOC_TEST_SIZE 256 +// Malloc fill pattern +#define MALLOC_FILL 0x55 + +extern uint32_t mbed_heap_start; +extern uint32_t mbed_heap_size; +extern uint32_t mbed_stack_isr_start; +extern uint32_t mbed_stack_isr_size; + +static uint32_t max_allocation_size = 0; + +static bool inrange(uint32_t addr, uint32_t start, uint32_t size); +static bool rangeinrange(uint32_t addr, uint32_t size, uint32_t start, uint32_t len); +static bool valid_fill(uint8_t * data, uint32_t size, uint8_t fill); +static bool allocate_and_fill_heap(void); +static bool check_and_free_heap(void); + +int main (void) { + GREENTEA_SETUP(30, "default_auto"); + + char c; + char * initial_stack = &c; + char *initial_heap; + + // Sanity check malloc + initial_heap = (char*)malloc(1); + if (initial_heap == NULL) { + printf("Unable to malloc a single byte\n"); + GREENTEA_TESTSUITE_RESULT(false); + } + + if (!inrange((uint32_t)initial_heap, mbed_heap_start, mbed_heap_size)) { + printf("Heap in wrong location\n"); + GREENTEA_TESTSUITE_RESULT(false); + } + // MSP stack should be very near end (test using within 128 bytes) + uint32_t msp = __get_MSP(); + if (!inrange(msp, mbed_stack_isr_start + mbed_stack_isr_size - 128, 128)) { + printf("Interrupt stack in wrong location\n"); + GREENTEA_TESTSUITE_RESULT(false); + } + + // Fully allocate the heap and stack + bool ret = true; + ret = ret && allocate_and_fill_heap(); + ret = ret && check_and_free_heap(); + + // Force a task switch so a stack check is performed + Thread::wait(10); + + printf("Total size dynamically allocated: %lu\n", max_allocation_size); + + GREENTEA_TESTSUITE_RESULT(ret); +} + +/* + * Return true if addr is in range [start:start+size) + */ +static bool inrange(uint32_t addr, uint32_t start, uint32_t size) +{ + return (addr >= start) && (addr < start + size) ? true : false; +} + +/* + * Return true if [addr:addr+size] is inside [start:start+len] + */ +static bool rangeinrange(uint32_t addr, uint32_t size, uint32_t start, uint32_t len) +{ + if (addr + size > start + len) { + return false; + } + if (addr < start) { + return false; + } + return true; +} + +/* + * Return true of the region is filled only the the specified fill value + */ +static bool valid_fill(uint8_t * data, uint32_t size, uint8_t fill) +{ + for (uint32_t i = 0; i < size; i++) { + if (data[i] != fill) { + return false; + } + } + return true; +} + +struct linked_list { + linked_list * next; + uint8_t data[MALLOC_TEST_SIZE]; +}; + +static linked_list *head = NULL; +static bool allocate_and_fill_heap() +{ + + linked_list *current; + + current = (linked_list*)malloc(sizeof(linked_list)); + if (0 == current) { + return false; + } + current->next = NULL; + memset((void*)current->data, MALLOC_FILL, sizeof(current->data)); + + // Allocate until malloc returns NULL + bool pass = true; + head = current; + while (true) { + + // Allocate + linked_list *temp = (linked_list*)malloc(sizeof(linked_list)); + if (NULL == temp) { + break; + } + if (!rangeinrange((uint32_t)temp, sizeof(linked_list), mbed_heap_start, mbed_heap_size)) { + printf("Memory allocation out of range\n"); + pass = false; + break; + } + + // Init + temp->next = NULL; + memset((void*)temp->data, MALLOC_FILL, sizeof(current->data)); + + // Add to list + current->next = temp; + current = temp; + } + return pass; +} + +static bool check_and_free_heap() +{ + uint32_t total_size = 0; + linked_list * current = head; + bool pass = true; + while (current != NULL) { + total_size += sizeof(linked_list); + if (!valid_fill(current->data, sizeof(current->data), MALLOC_FILL)) { + pass = false; + } + linked_list * next = current->next; + free(current); + current = next; + } + + max_allocation_size = total_size; + return pass; +} From 69bf173e221a1e0b1a81e3793970659fd2c6fb05 Mon Sep 17 00:00:00 2001 From: Russ Butler Date: Mon, 8 Aug 2016 17:11:47 -0500 Subject: [PATCH 7/9] Decrease NUC472 interrupt stack size Decrease the interrupt stack of the NUC472 from 12KB to 8KB. This frees up enough space to allow the core tests to run. --- .../TARGET_NUMAKER_PFM_NUC472/TOOLCHAIN_IAR/NUC472_442.icf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/targets/cmsis/TARGET_NUVOTON/TARGET_NUC472/TARGET_NUMAKER_PFM_NUC472/TOOLCHAIN_IAR/NUC472_442.icf b/hal/targets/cmsis/TARGET_NUVOTON/TARGET_NUC472/TARGET_NUMAKER_PFM_NUC472/TOOLCHAIN_IAR/NUC472_442.icf index 6dd7603a14..9addb2df09 100644 --- a/hal/targets/cmsis/TARGET_NUVOTON/TARGET_NUC472/TARGET_NUMAKER_PFM_NUC472/TOOLCHAIN_IAR/NUC472_442.icf +++ b/hal/targets/cmsis/TARGET_NUVOTON/TARGET_NUC472/TARGET_NUMAKER_PFM_NUC472/TOOLCHAIN_IAR/NUC472_442.icf @@ -11,7 +11,7 @@ define symbol __ICFEDIT_region_IRAM_end__ = 0x20010000; define symbol __ICFEDIT_region_XRAM_start__ = 0x60000000; define symbol __ICFEDIT_region_XRAM_end__ = 0x60100000; /*-Sizes-*/ -define symbol __ICFEDIT_size_cstack__ = 0x3000; +define symbol __ICFEDIT_size_cstack__ = 0x2000; define symbol __ICFEDIT_size_heap__ = 0xC0000; /**** End of ICF editor section. ###ICF###*/ From 3587a08f8e5711ba59cf5754ad4089e15970a61e Mon Sep 17 00:00:00 2001 From: Russ Butler Date: Mon, 8 Aug 2016 21:42:31 -0500 Subject: [PATCH 8/9] Fix nrf52 initial stack pointer in ARMCC Set the initial stack pointer to the end of ram so it matches INITIAL_SP defined in RTX_CM_lib.h. --- .../TARGET_MCU_NRF52832/TOOLCHAIN_ARM_STD/startup_nrf52832.s | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hal/targets/cmsis/TARGET_NORDIC/TARGET_NRF5/TARGET_MCU_NRF52832/TOOLCHAIN_ARM_STD/startup_nrf52832.s b/hal/targets/cmsis/TARGET_NORDIC/TARGET_NRF5/TARGET_MCU_NRF52832/TOOLCHAIN_ARM_STD/startup_nrf52832.s index dca7388684..4a783efe38 100644 --- a/hal/targets/cmsis/TARGET_NORDIC/TARGET_NRF5/TARGET_MCU_NRF52832/TOOLCHAIN_ARM_STD/startup_nrf52832.s +++ b/hal/targets/cmsis/TARGET_NORDIC/TARGET_NRF5/TARGET_MCU_NRF52832/TOOLCHAIN_ARM_STD/startup_nrf52832.s @@ -25,7 +25,7 @@ ; POSSIBILITY OF SUCH DAMAGE. ; ---------------------------------------------------------------------------*/ -__initial_sp EQU 0x20008000 +__initial_sp EQU 0x20010000 PRESERVE8 THUMB From d9ac33d0c3eaab39dbf5f4d7290e1b4b54e81f0e Mon Sep 17 00:00:00 2001 From: Russ Butler Date: Tue, 9 Aug 2016 14:32:08 -0500 Subject: [PATCH 9/9] Increase interrupt stack size for K64F The config store tests use more than 2K of the interrupt stack, causing an overflow. This patch bumps the K64F interrupt stack size to 4K for ARMCC and GCC. The IAR interrupt stack is left untouched since it is 32K. --- rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h b/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h index 241d3153e8..767f9edb11 100644 --- a/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h +++ b/rtos/rtx/TARGET_CORTEX_M/RTX_CM_lib.h @@ -426,6 +426,9 @@ extern uint32_t __StackTop[]; #else #define INITIAL_SP (0x20030000UL) #endif +#if defined(__CC_ARM) || defined(__GNUC__) +#define ISR_STACK_SIZE (0x1000) +#endif #elif defined(TARGET_K22F) #define INITIAL_SP (0x20010000UL)