/* ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio. This file is part of ChibiOS/RT. ChibiOS/RT is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. ChibiOS/RT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /** * @file ARMCMx/crt0.c * @brief Generic ARMvx-M (Cortex-M0/M1/M3/M4) startup file for ChibiOS/RT. * * @addtogroup ARMCMx_CORE * @{ */ #include "chtypes.h" #define FALSE 0 #define TRUE (!FALSE) typedef void (*funcp_t)(void); typedef funcp_t * funcpp_t; /** * @brief Control special register initialization value. * @details The system is setup to run in privileged mode using the PSP * stack (dual stack mode). */ #if !defined(CRT0_CONTROL_INIT) || defined(__DOXYGEN__) #define CRT0_CONTROL_INIT 0x00000002 #endif /** * @brief DATA segment initialization switch. */ #if !defined(CRT0_INIT_DATA) || defined(__DOXYGEN__) #define CRT0_INIT_DATA TRUE #endif /** * @brief BSS segment initialization switch. */ #if !defined(CRT0_INIT_BSS) || defined(__DOXYGEN__) #define CRT0_INIT_BSS TRUE #endif /** * @brief Constructors invocation switch. */ #if !defined(CRT0_CALL_CONSTRUCTORS) || defined(__DOXYGEN__) #define CRT0_CALL_CONSTRUCTORS TRUE #endif /** * @brief Destructors invocation switch. */ #if !defined(CRT0_CALL_DESTRUCTORS) || defined(__DOXYGEN__) #define CRT0_CALL_DESTRUCTORS TRUE #endif #define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0)) /** * @brief Ram end. * @details This symbol must be exported by the linker script and represents * the location after the last RAM location. */ 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__; /** * @brief ROM image of the data segment start. * @pre The symbol must be aligned to a 32 bits boundary. */ extern uint32_t _textdata; /** * @brief Data segment start. * @pre The symbol must be aligned to a 32 bits boundary. */ extern uint32_t _data; /** * @brief Data segment end. * @pre The symbol must be aligned to a 32 bits boundary. */ extern uint32_t _edata; /** * @brief BSS segment start. * @pre The symbol must be aligned to a 32 bits boundary. */ extern uint32_t _bss_start; /** * @brief BSS segment end. * @pre The symbol must be aligned to a 32 bits boundary. */ extern uint32_t _bss_end; /** * @brief Constructors table start. * @pre The symbol must be aligned to a 32 bits boundary. */ extern funcp_t __init_array_start; /** * @brief Constructors table end. * @pre The symbol must be aligned to a 32 bits boundary. */ extern funcp_t __init_array_end; /** * @brief Destructors table start. * @pre The symbol must be aligned to a 32 bits boundary. */ extern funcp_t __fini_array_start; /** * @brief Destructors table end. * @pre The symbol must be aligned to a 32 bits boundary. */ extern funcp_t __fini_array_end; /** * @brief Application @p main() function. */ extern void main(void); /** * @brief Early initialization. * @details This hook is invoked immediately after the stack initialization * and before the DATA and BSS segments initialization. The * default behavior is to do nothing. * @note This function is a weak symbol. */ #if !defined(__DOXYGEN__) __attribute__((weak)) #endif void __early_init(void) {} /** * @brief Late initialization. * @details This hook is invoked after the DATA and BSS segments * initialization and before any static constructor. The * default behavior is to do nothing. * @note This function is a weak symbol. */ #if !defined(__DOXYGEN__) __attribute__((weak)) #endif void __late_init(void) {} /** * @brief Default @p main() function exit handler. * @details This handler is invoked or the @p main() function exit. The * default behavior is to enter an infinite loop. * @note This function is a weak symbol. */ #if !defined(__DOXYGEN__) __attribute__((weak, noreturn)) #endif void _default_exit(void) { while (1) ; } /** * @brief Reset vector. */ #if !defined(__DOXYGEN__) __attribute__((noreturn)) #endif void ResetHandler(void) { uint32_t psp, ctl; /* Process Stack initialization, it is allocated below the main stack. The 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__); asm volatile ("msr PSP, %0" : : "r" (psp)); ctl = CRT0_CONTROL_INIT; asm volatile ("msr CONTROL, %0" : : "r" (ctl)); asm volatile ("isb"); /* Early initialization hook invocation.*/ __early_init(); #if CRT0_INIT_DATA /* DATA segment initialization.*/ { uint32_t *tp, *dp; tp = &_textdata; dp = &_data; while (dp < &_edata) *dp++ = *tp++; } #endif #if CRT0_INIT_BSS /* BSS segment initialization.*/ { uint32_t *bp; bp = &_bss_start; while (bp < &_bss_end) *bp++ = 0; } #endif /* Late initialization hook invocation.*/ __late_init(); #if CRT0_CALL_CONSTRUCTORS /* Constructors invocation.*/ { funcpp_t fpp = &__init_array_start; while (fpp < &__init_array_end) { (*fpp)(); fpp++; } } #endif /* Invoking application main() function.*/ main(); #if CRT0_CALL_DESTRUCTORS /* Destructors invocation.*/ { funcpp_t fpp = &__fini_array_start; while (fpp < &__fini_array_end) { (*fpp)(); fpp++; } } #endif /* Invoking the exit handler.*/ _default_exit(); } /** @} */