Merge pull request #2402 from c1728p9/main_thread_stack_checking_alt_impl

Main thread stack checking alt impl
pull/2423/head
Sam Grove 2016-08-11 01:16:12 +01:00 committed by GitHub
commit 4382db1a6e
8 changed files with 369 additions and 110 deletions

View File

@ -23,6 +23,8 @@
#include "mbed_interface.h"
#include "SingletonPtr.h"
#include "PlatformMutex.h"
#include "mbed_error.h"
#include <stdlib.h>
#if DEVICE_STDIO_MESSAGES
#include <stdio.h>
#endif
@ -68,6 +70,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 +602,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;
}
@ -714,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);
}
}

View File

@ -25,7 +25,7 @@
; POSSIBILITY OF SUCH DAMAGE.
; ---------------------------------------------------------------------------*/
__initial_sp EQU 0x20008000
__initial_sp EQU 0x20010000
PRESERVE8
THUMB

View File

@ -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###*/

View File

@ -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
}

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

@ -350,7 +350,46 @@ __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};
#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};
/*
* 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)
@ -381,12 +420,15 @@ 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
#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)
@ -534,19 +576,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 +604,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 +701,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 +723,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 +743,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 +760,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 +803,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 +880,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();

View File

@ -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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#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;
}

View File

@ -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)

View File

@ -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
}
/*----------------------------------------------------------------------------