diff --git a/demos/ARMCM3-STM32F103/ch.ld b/demos/ARMCM3-STM32F103/ch.ld index 4d97e7682..f929c0832 100644 --- a/demos/ARMCM3-STM32F103/ch.ld +++ b/demos/ARMCM3-STM32F103/ch.ld @@ -23,7 +23,6 @@ */ __main_stack_size__ = 0x0400; __process_stack_size__ = 0x0400; -__stacks_total_size__ = __main_stack_size__ + __process_stack_size__; MEMORY { @@ -98,6 +97,21 @@ SECTIONS _etext = .; _textdata = _etext; + .stacks : + { + . = ALIGN(8); + __main_stack_base__ = .; + . += __main_stack_size__; + . = ALIGN(8); + __main_stack_end__ = .; + __process_stack_base__ = .; + __main_thread_stack_base__ = .; + . += __process_stack_size__; + . = ALIGN(8); + __process_stack_end__ = .; + __main_thread_stack_end__ = .; + } > ram + .data : { PROVIDE(_data = .); @@ -127,4 +141,4 @@ PROVIDE(end = .); _end = .; __heap_base__ = _end; -__heap_end__ = __ram_end__ - __stacks_total_size__; +__heap_end__ = __ram_end__; diff --git a/demos/ARMCM3-STM32F103/chconf.h b/demos/ARMCM3-STM32F103/chconf.h index c9c4c286a..cdf4ee616 100644 --- a/demos/ARMCM3-STM32F103/chconf.h +++ b/demos/ARMCM3-STM32F103/chconf.h @@ -395,7 +395,7 @@ * @p panic_msg variable set to @p NULL. */ #if !defined(CH_DBG_ENABLE_STACK_CHECK) || defined(__DOXYGEN__) -#define CH_DBG_ENABLE_STACK_CHECK FALSE +#define CH_DBG_ENABLE_STACK_CHECK TRUE #endif /** diff --git a/os/kernel/include/chschd.h b/os/kernel/include/chschd.h index e154da863..cd545a05e 100644 --- a/os/kernel/include/chschd.h +++ b/os/kernel/include/chschd.h @@ -76,12 +76,12 @@ typedef struct { initialized to zero. */ struct context r_ctx; /**< @brief Not used, present because offsets. */ -#if CH_USE_REGISTRY +#if CH_USE_REGISTRY || defined(__DOXYGEN__) Thread *r_newer; /**< @brief Newer registry element. */ Thread *r_older; /**< @brief Older registry element. */ #endif /* End of the fields shared with the Thread structure.*/ -#if CH_TIME_QUANTUM > 0 +#if (CH_TIME_QUANTUM > 0) || defined(__DOXYGEN__) cnt_t r_preempt; /**< @brief Round robin counter. */ #endif Thread *r_current; /**< @brief The currently running diff --git a/os/kernel/include/chthreads.h b/os/kernel/include/chthreads.h index e0f1b3e95..b02960bd4 100644 --- a/os/kernel/include/chthreads.h +++ b/os/kernel/include/chthreads.h @@ -44,16 +44,22 @@ struct Thread { /* End of the fields shared with the ThreadsQueue structure. */ tprio_t p_prio; /**< @brief Thread priority. */ struct context p_ctx; /**< @brief Processor context. */ -#if CH_USE_REGISTRY +#if CH_USE_REGISTRY || defined(__DOXYGEN__) Thread *p_newer; /**< @brief Newer registry element. */ Thread *p_older; /**< @brief Older registry element. */ #endif /* End of the fields shared with the ReadyList structure. */ -#if CH_USE_REGISTRY +#if CH_USE_REGISTRY || defined(__DOXYGEN__) /** * @brief Thread name or @p NULL. */ const char *p_name; +#endif +#if CH_DBG_ENABLE_STACK_CHECK || defined(__DOXYGEN__) + /** + * @brief Thread stack boundary. + */ + stkalign_t *p_stklimit; #endif /** * @brief Current thread state. @@ -63,19 +69,19 @@ struct Thread { * @brief Various thread flags. */ tmode_t p_flags; -#if CH_USE_DYNAMIC +#if CH_USE_DYNAMIC || defined(__DOXYGEN__) /** * @brief References to this thread. */ trefs_t p_refs; #endif -#if CH_USE_NESTED_LOCKS +#if CH_USE_NESTED_LOCKS || defined(__DOXYGEN__) /** * @brief Number of nested locks. */ cnt_t p_locks; #endif -#if CH_DBG_THREADS_PROFILING +#if CH_DBG_THREADS_PROFILING || defined(__DOXYGEN__) /** * @brief Thread consumed time in ticks. * @note This field can overflow. @@ -109,22 +115,22 @@ struct Thread { * states. */ void *wtobjp; -#if CH_USE_EVENTS +#if CH_USE_EVENTS || defined(__DOXYGEN__) /** * @brief Enabled events mask. - * @note This field is only valied while the thread is in the + * @note This field is only valid while the thread is in the * @p THD_STATE_WTOREVT or @p THD_STATE_WTANDEVT states. */ eventmask_t ewmask; #endif } p_u; -#if CH_USE_WAITEXIT +#if CH_USE_WAITEXIT || defined(__DOXYGEN__) /** * @brief Termination waiting list. */ ThreadsList p_waiting; #endif -#if CH_USE_MESSAGES +#if CH_USE_MESSAGES || defined(__DOXYGEN__) /** * @brief Messages queue. */ @@ -134,13 +140,13 @@ struct Thread { */ msg_t p_msg; #endif -#if CH_USE_EVENTS +#if CH_USE_EVENTS || defined(__DOXYGEN__) /** * @brief Pending events mask. */ eventmask_t p_epending; #endif -#if CH_USE_MUTEXES +#if CH_USE_MUTEXES || defined(__DOXYGEN__) /** * @brief List of the mutexes owned by this thread. * @note The list is terminated by a @p NULL in this field. @@ -151,7 +157,7 @@ struct Thread { */ tprio_t p_realprio; #endif -#if CH_USE_DYNAMIC && CH_USE_MEMPOOLS +#if (CH_USE_DYNAMIC && CH_USE_MEMPOOLS) || defined(__DOXYGEN__) /** * @brief Memory Pool where the thread workspace is returned. */ diff --git a/os/kernel/src/chsys.c b/os/kernel/src/chsys.c index 8d9ce4905..4c8cd708d 100644 --- a/os/kernel/src/chsys.c +++ b/os/kernel/src/chsys.c @@ -77,6 +77,9 @@ void _idle_thread(void *p) { */ void chSysInit(void) { static Thread mainthread; +#if CH_DBG_ENABLE_STACK_CHECK + extern stkalign_t __main_thread_stack_base__; +#endif port_init(); _scheduler_init(); @@ -94,6 +97,9 @@ void chSysInit(void) { /* Now this instructions flow becomes the main thread.*/ setcurrp(_thread_init(&mainthread, NORMALPRIO)); currp->p_state = THD_STATE_CURRENT; +#if CH_DBG_ENABLE_STACK_CHECK + currp->p_stklimit = &__main_thread_stack_base__; +#endif chSysEnable(); chRegSetThreadName("main"); diff --git a/os/kernel/src/chthreads.c b/os/kernel/src/chthreads.c index b68263a7b..182de7673 100644 --- a/os/kernel/src/chthreads.c +++ b/os/kernel/src/chthreads.c @@ -99,6 +99,9 @@ Thread *_thread_init(Thread *tp, tprio_t prio) { #if CH_USE_MESSAGES queue_init(&tp->p_msgqueue); #endif +#if CH_DBG_ENABLE_STACK_CHECK + tp->p_stklimit = (stkalign_t *)(tp + 1); +#endif #if defined(THREAD_EXT_INIT_HOOK) THREAD_EXT_INIT_HOOK(tp); #endif diff --git a/os/ports/GCC/ARMCMx/LPC11xx/vectors.c b/os/ports/GCC/ARMCMx/LPC11xx/vectors.c index 63b343ea2..527d82836 100644 --- a/os/ports/GCC/ARMCMx/LPC11xx/vectors.c +++ b/os/ports/GCC/ARMCMx/LPC11xx/vectors.c @@ -31,7 +31,7 @@ #include "ch.h" #if !defined(__DOXYGEN__) -extern void __ram_end__(void); +extern void __main_stack_end__(void); extern void ResetHandler(void); extern void NMIVector(void); extern void HardFaultVector(void); @@ -88,7 +88,7 @@ extern void VectorBC(void); __attribute__ ((section("vectors"))) #endif void (*_vectors[])(void) = { - __ram_end__, ResetHandler, NMIVector, HardFaultVector, + __main_stack_end__, ResetHandler, NMIVector, HardFaultVector, MemManageVector, BusFaultVector, UsageFaultVector, Vector1C, Vector20, Vector24, Vector28, SVCallVector, DebugMonitorVector, Vector34, PendSVVector, SysTickVector, diff --git a/os/ports/GCC/ARMCMx/LPC13xx/vectors.c b/os/ports/GCC/ARMCMx/LPC13xx/vectors.c index 1e27c4fc8..14bc798dd 100644 --- a/os/ports/GCC/ARMCMx/LPC13xx/vectors.c +++ b/os/ports/GCC/ARMCMx/LPC13xx/vectors.c @@ -31,7 +31,7 @@ #include "ch.h" #if !defined(__DOXYGEN__) -extern void __ram_end__(void); +extern void __main_stack_end__(void); extern void ResetHandler(void); extern void NMIVector(void); extern void HardFaultVector(void); @@ -112,7 +112,7 @@ extern void Vector11C(void); __attribute__ ((section("vectors"))) #endif void (*_vectors[])(void) = { - __ram_end__, ResetHandler, NMIVector, HardFaultVector, + __main_stack_end__, ResetHandler, NMIVector, HardFaultVector, MemManageVector, BusFaultVector, UsageFaultVector, Vector1C, Vector20, Vector24, Vector28, SVCallVector, DebugMonitorVector, Vector34, PendSVVector, SysTickVector, diff --git a/os/ports/GCC/ARMCMx/STM32/port.mk b/os/ports/GCC/ARMCMx/STM32/port.mk index 104b22e42..1e5a51a8d 100644 --- a/os/ports/GCC/ARMCMx/STM32/port.mk +++ b/os/ports/GCC/ARMCMx/STM32/port.mk @@ -9,3 +9,6 @@ PORTASM = PORTINC = ${CHIBIOS}/os/ports/GCC/ARMCMx \ ${CHIBIOS}/os/ports/GCC/ARMCMx/STM32 + +PORTLD = ${CHIBIOS}/os/ports/GCC/ARMCMx/STM32/ld + diff --git a/os/ports/GCC/ARMCMx/STM32/vectors.c b/os/ports/GCC/ARMCMx/STM32/vectors.c index f12e2e867..e4d1bcb28 100644 --- a/os/ports/GCC/ARMCMx/STM32/vectors.c +++ b/os/ports/GCC/ARMCMx/STM32/vectors.c @@ -38,7 +38,7 @@ #endif #if !defined(__DOXYGEN__) -extern void __ram_end__(void); +extern void __main_stack_end__(void); extern void ResetHandler(void); extern void NMIVector(void); extern void HardFaultVector(void); @@ -138,7 +138,7 @@ extern void Vector14C(void); __attribute__ ((section("vectors"))) #endif void (*_vectors[])(void) = { - __ram_end__, ResetHandler, NMIVector, HardFaultVector, + __main_stack_end__, ResetHandler, NMIVector, HardFaultVector, MemManageVector, BusFaultVector, UsageFaultVector, Vector1C, Vector20, Vector24, Vector28, SVCallVector, DebugMonitorVector, Vector34, PendSVVector, SysTickVector, diff --git a/os/ports/GCC/ARMCMx/chcore_v6m.h b/os/ports/GCC/ARMCMx/chcore_v6m.h index 2141ee468..bb6e6083b 100644 --- a/os/ports/GCC/ARMCMx/chcore_v6m.h +++ b/os/ports/GCC/ARMCMx/chcore_v6m.h @@ -242,8 +242,8 @@ struct intctx { #define port_switch(ntp, otp) _port_switch(ntp, otp) #else #define port_switch(ntp, otp) { \ - register struct intctx *r13 asm ("r13"); \ - if ((void *)(r13 - 1) < (void *)(otp + 1)) \ + register struct intctx *r13 asm ("r13"); \ + if ((stkalign_t *)(r13 - 1) < otp->p_stklimit) \ chDbgPanic("stack overflow"); \ _port_switch(ntp, otp); \ } diff --git a/os/ports/GCC/ARMCMx/chcore_v7m.c b/os/ports/GCC/ARMCMx/chcore_v7m.c index 897c90a96..39711ce79 100644 --- a/os/ports/GCC/ARMCMx/chcore_v7m.c +++ b/os/ports/GCC/ARMCMx/chcore_v7m.c @@ -166,15 +166,7 @@ void _port_switch_from_isr(void) { #if !defined(__DOXYGEN__) __attribute__((naked)) #endif -void port_switch(Thread *ntp, Thread *otp) { - -#if CH_DBG_ENABLE_STACK_CHECK - /* Stack overflow check, if enabled.*/ - register struct intctx *r13 asm ("r13"); - if ((void *)(r13 - 1) < (void *)(otp + 1)) - asm volatile ("movs r0, #0 \n\t" - "b chDbgPanic"); -#endif /* CH_DBG_ENABLE_STACK_CHECK */ +void _port_switch(Thread *ntp, Thread *otp) { PUSH_CONTEXT(); diff --git a/os/ports/GCC/ARMCMx/chcore_v7m.h b/os/ports/GCC/ARMCMx/chcore_v7m.h index 297bd4e54..afb3ac21d 100644 --- a/os/ports/GCC/ARMCMx/chcore_v7m.h +++ b/os/ports/GCC/ARMCMx/chcore_v7m.h @@ -314,11 +314,32 @@ struct intctx { #define port_wait_for_interrupt() #endif +/** + * @brief Performs a context switch between two threads. + * @details This is the most critical code in any port, this function + * is responsible for the context switch between 2 threads. + * @note The implementation of this code affects directly the context + * switch performance so optimize here as much as you can. + * + * @param[in] ntp the thread to be switched in + * @param[in] otp the thread to be switched out + */ +#if !defined(CH_DBG_ENABLE_STACK_CHECK) || defined(__DOXYGEN__) +#define port_switch(ntp, otp) _port_switch(ntp, otp) +#else +#define port_switch(ntp, otp) { \ + register struct intctx *r13 asm ("r13"); \ + if ((stkalign_t *)(r13 - 1) < otp->p_stklimit) \ + chDbgPanic("stack overflow"); \ + _port_switch(ntp, otp); \ +} +#endif + #ifdef __cplusplus extern "C" { #endif void port_halt(void); - void port_switch(Thread *ntp, Thread *otp); + void _port_switch(Thread *ntp, Thread *otp); void _port_irq_epilogue(void); void _port_switch_from_isr(void); void _port_thread_start(void); diff --git a/os/ports/GCC/ARMCMx/crt0.c b/os/ports/GCC/ARMCMx/crt0.c index 0bb88dd83..73dca119e 100644 --- a/os/ports/GCC/ARMCMx/crt0.c +++ b/os/ports/GCC/ARMCMx/crt0.c @@ -73,28 +73,11 @@ typedef funcp_t * funcpp_t; #define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0)) /** - * @brief Ram end. + * @brief Main thread stack initial position. * @details This symbol must be exported by the linker script and represents - * the location after the last RAM location. + * the main thread stack initial position. */ -extern uint8_t __ram_end__; - -/** - * @brief Main stack size. - * @details This symbol must be exported by the linker script and represents - * the main stack size. - * @note The main stack is the stack where interrupts and exceptions are - * processed. - */ -extern uint8_t __main_stack_size__; - -/** - * @brief Process stack size. - * @details This symbol must be exported by the linker script and represents - * the process stack size. - * @note The process stack is the stack used by the @p main() function. - */ -extern uint8_t __process_stack_size__; +extern uint8_t __process_stack_end__; /** * @brief ROM image of the data segment start. @@ -206,7 +189,7 @@ void ResetHandler(void) { main stack is assumed to be allocated starting from @p __ram_end__ extending downward.*/ asm volatile ("cpsid i"); - psp = SYMVAL(__ram_end__) - SYMVAL(__main_stack_size__); + psp = SYMVAL(__process_stack_end__); asm volatile ("msr PSP, %0" : : "r" (psp)); ctl = CRT0_CONTROL_INIT; diff --git a/readme.txt b/readme.txt index 3578a38aa..8a8bbac1b 100644 --- a/readme.txt +++ b/readme.txt @@ -87,6 +87,15 @@ (backported to 2.2.4). - FIX: Fixed timeout problem in the lwIP interface layer (bug 3302420) (backported to 2.2.4). +- NEW: Improved stack checking and reorganized memory map for the Cortex-Mx + demos. Now stacks are allocated at the start of the RAM, an overflow of the + exception stack now triggers an exception (it could went unnoticed before). + The process stack is organized to be checked on context switch like other + threads. Now all threads have an explicit stack boundary pointer. + (to be completed, most demos have to be edited) + (documentation to be updated) + (change to be ported to IAR and Keil ports) + (change to be ported to ARM and other ports) - NEW: Added debug plugin for Eclipse under ./tools/eclipse (backported to 2.2.7). - NEW: The debug macros chDbgCheck() and chDbgAssert() now can be externally @@ -96,6 +105,7 @@ - NEW: Added provisional support for STM32L1xx and STM32F2xx. Because of this some directories related to the STM32 have been renamed, your makefiles may require adjustments. + (change to be ported to IAR and Keil build files) - NEW: Added a custom rule to the various rules.mk files, now it is possible to add an user rule into the Makefiles. - NEW: Improvements to the trace buffer, now it stores a full thread pointer @@ -450,7 +460,7 @@ (backported to 2.0.6). - FIX: Incorrect AT91SAM7X initialization, thanks Leszek (bug 3075354) (backported to 2.0.5). -- FIX: Fixed race condition in function chSchGoSleepTimeoutS(), thanks Balázs +- FIX: Fixed race condition in function chSchGoSleepTimeoutS(), thanks Balďż˝zs (bug 3074984)(backported to 2.0.5). - FIX: Fixed race condition in threads creation (bug 3069854)(backported to 2.0.5).