From 39209c73a3991a40a0cdda938fb6982038ac3e60 Mon Sep 17 00:00:00 2001 From: Martin Budden Date: Fri, 26 Aug 2016 14:33:20 +0100 Subject: [PATCH] Stack watermarking --- Makefile | 1 + src/main/drivers/stack_check.c | 64 ++++++++++++++++++++++++++++ src/main/main.c | 5 ++- src/main/scheduler/scheduler.h | 3 ++ src/main/scheduler/scheduler_tasks.c | 9 ++++ src/main/scheduler/scheduler_tasks.h | 1 + src/main/target/CJMCU/target.h | 3 ++ src/main/target/stm32_flash.ld | 5 ++- 8 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 src/main/drivers/stack_check.c diff --git a/Makefile b/Makefile index d66da024f..c6dd2234e 100644 --- a/Makefile +++ b/Makefile @@ -391,6 +391,7 @@ COMMON_SRC = \ drivers/serial.c \ drivers/serial_uart.c \ drivers/sound_beeper.c \ + drivers/stack_check.c \ drivers/system.c \ drivers/timer.c \ flight/failsafe.c \ diff --git a/src/main/drivers/stack_check.c b/src/main/drivers/stack_check.c new file mode 100644 index 000000000..fed81d177 --- /dev/null +++ b/src/main/drivers/stack_check.c @@ -0,0 +1,64 @@ +/* + * stack_check.c + * + * Created on: 23 Aug 2016 + * Author: martinbudden + */ + +#include +#include +#include + +#include "platform.h" + +#ifdef STACK_CHECK + +#include "build/debug.h" + +#define STACK_FILL_CHAR 0xa5 + +extern char _estack; // end of stack, declared in .LD file +extern char _Min_Stack_Size; // declared in .LD file + +/* + * The ARM processor uses a full descending stack. This means the stack pointer holds the address + * of the last stacked item in memory. When the processor pushes a new item onto the stack, + * it decrements the stack pointer and then writes the item to the new memory location. + * + * + * RAM layout is generally as below, although some targets vary + * + * F1 Boards + * RAM is origin 0x20000000 length 20K that is: + * 0x20000000 to 0x20005000 + * + * F3 Boards + * RAM is origin 0x20000000 length 40K that is: + * 0x20000000 to 0x2000a000 + * + * F4 Boards + * RAM is origin 0x20000000 length 128K that is: + * 0x20000000 to 0x20020000 + * + */ +void taskStackCheck(void) +{ + char * const stackHighMem = &_estack; + const uint32_t stackSize = (uint32_t)&_Min_Stack_Size; + char * const stackLowMem = stackHighMem - stackSize; + const char * const stackCurrent = (char *)&stackLowMem; + + char *p; + for (p = stackLowMem; p < stackCurrent; ++p) { + if (*p != STACK_FILL_CHAR) { + break; + } + } +#ifdef DEBUG_STACK + debug[0] = (uint32_t)stackHighMem & 0xffff; + debug[1] = (uint32_t)stackLowMem & 0xffff; + debug[2] = (uint32_t)stackCurrent & 0xffff; + debug[3] = (uint32_t)p & 0xffff; // watermark +#endif +} +#endif diff --git a/src/main/main.c b/src/main/main.c index a0e3767fd..294a2c585 100644 --- a/src/main/main.c +++ b/src/main/main.c @@ -608,6 +608,9 @@ int main(void) #ifdef LED_STRIP setTaskEnabled(TASK_LEDSTRIP, feature(FEATURE_LED_STRIP)); #endif +#ifdef STACK_CHECK + setTaskEnabled(TASK_STACK_CHECK, true); +#endif while (true) { scheduler(); @@ -699,4 +702,4 @@ void HardFault_Handler(void) } } -#endif \ No newline at end of file +#endif diff --git a/src/main/scheduler/scheduler.h b/src/main/scheduler/scheduler.h index 2bd7b47e2..5e82a3daa 100755 --- a/src/main/scheduler/scheduler.h +++ b/src/main/scheduler/scheduler.h @@ -68,6 +68,9 @@ typedef enum { #ifdef LED_STRIP TASK_LEDSTRIP, #endif +#ifdef STACK_CHECK + TASK_STACK_CHECK, +#endif /* Count of real tasks */ TASK_COUNT, diff --git a/src/main/scheduler/scheduler_tasks.c b/src/main/scheduler/scheduler_tasks.c index d58235a11..ca9a80add 100755 --- a/src/main/scheduler/scheduler_tasks.c +++ b/src/main/scheduler/scheduler_tasks.c @@ -129,4 +129,13 @@ cfTask_t cfTasks[TASK_COUNT] = { .staticPriority = TASK_PRIORITY_IDLE, }, #endif + +#ifdef STACK_CHECK + [TASK_STACK_CHECK] = { + .taskName = "STACKCHECK", + .taskFunc = taskStackCheck, + .desiredPeriod = 1000000 / 10, // 10 Hz + .staticPriority = TASK_PRIORITY_IDLE, + }, +#endif }; diff --git a/src/main/scheduler/scheduler_tasks.h b/src/main/scheduler/scheduler_tasks.h index 995e2b303..6d1c86228 100644 --- a/src/main/scheduler/scheduler_tasks.h +++ b/src/main/scheduler/scheduler_tasks.h @@ -33,4 +33,5 @@ void taskUpdateDisplay(void); void taskTelemetry(void); void taskLedStrip(void); void taskSystem(void); +void taskStackCheck(void); diff --git a/src/main/target/CJMCU/target.h b/src/main/target/CJMCU/target.h index 2c71de593..8590c0311 100644 --- a/src/main/target/CJMCU/target.h +++ b/src/main/target/CJMCU/target.h @@ -109,6 +109,9 @@ #undef BLACKBOX #endif +#define STACK_CHECK +#define DEBUG_STACK + // Number of available PWM outputs #define MAX_PWM_OUTPUT_PORTS 4 diff --git a/src/main/target/stm32_flash.ld b/src/main/target/stm32_flash.ld index 40bc9965b..883dc7c41 100644 --- a/src/main/target/stm32_flash.ld +++ b/src/main/target/stm32_flash.ld @@ -110,6 +110,9 @@ SECTIONS } >RAM /* User_heap_stack section, used to check that there is enough RAM left */ + _heap_stack_end = ORIGIN(RAM)+LENGTH(RAM) - 8; /* 8 bytes to allow for alignment */ + _heap_stack_begin = _heap_stack_end - _Min_Stack_Size - _Min_Heap_Size; + . = _heap_stack_begin; ._user_heap_stack : { . = ALIGN(4); @@ -118,7 +121,7 @@ SECTIONS . = . + _Min_Heap_Size; . = . + _Min_Stack_Size; . = ALIGN(4); - } >RAM + } >RAM = 0xa5 /* MEMORY_bank1 section, code must be located here explicitly */ /* Example: extern int foo(void) __attribute__ ((section (".mb1text"))); */