Refactor boot process

Refactor the Mbed 5 boot process to make is simpler and more modular.
This is done by breaking the boot sequence into 4 distinct steps -
Target setup, Toolchain setup, RTOS setup and Mbed setup. This patch
also move toolchain specific code into a per toolchain folder to make
it more maintainable.
pull/7794/head
Russ Butler 2018-08-13 10:33:57 -05:00
parent ec19bf1de4
commit 325565bf79
7 changed files with 884 additions and 705 deletions

View File

@ -0,0 +1,68 @@
/* mbed Microcontroller Library
* Copyright (c) 2018-2018 ARM Limited
*
* 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 <stdlib.h>
#include <string.h>
#include "mbed_boot.h"
#include "mbed_assert.h"
/* Symbols that are typically defined in startup_<mcu>.S */
extern uint32_t __initial_sp[];
extern uint32_t __heap_base[];
extern uint32_t __heap_limit[];
/*
* mbed entry point for the MICROLIB toolchain
*
* Override the microlib function _main_init to run code earlier in
* the boot sequence. The function _main_init is responsible for invoking main.
* This function must be placed in the ".ARM.Collect" section
* or it won't get called.
*/
void _main_init(void) __attribute__((section(".ARM.Collect$$$$000000FF")));
void _main_init(void)
{
/* microlib only supports the two region memory model */
mbed_heap_start = (unsigned char*)__heap_base;
mbed_heap_size = (uint32_t)__heap_base - (uint32_t)__heap_limit;
mbed_stack_isr_start = (unsigned char*)((uint32_t)__initial_sp - ISR_STACK_SIZE);
mbed_stack_isr_size = ISR_STACK_SIZE;
mbed_init();
mbed_rtos_start();
}
void $Sub$$__cpp_initialize__aeabi_(void);
void $Super$$__cpp_initialize__aeabi_(void);
void $Sub$$__cpp_initialize__aeabi_(void)
{
/* This should invoke C++ initializers but we keep
* this empty and invoke them RTX is initialized.
*/
}
void mbed_toolchain_init()
{
/* Run the C++ global object constructors */
$Super$$__cpp_initialize__aeabi_();
}
MBED_WEAK void __aeabi_assert(const char *expr, const char *file, int line)
{
mbed_assert_internal(expr, file, line);
}

View File

@ -0,0 +1,257 @@
/* mbed Microcontroller Library
* Copyright (c) 2018-2018 ARM Limited
*
* 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 <stdlib.h>
#include <string.h>
#include "cmsis.h"
#include "mbed_critical.h"
#include "mbed_boot.h"
#include <rt_misc.h>
#include "mbed_rtos_storage.h"
#include "cmsis_os2.h"
__value_in_regs struct __argc_argv __rt_lib_init(unsigned heapbase, unsigned heaptop);
void _platform_post_stackheap_init(void);
#if !defined(HEAP_START)
/* Defined by linker script */
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))
#endif
/*
* Note - Overriding the function __cpp_initialize__aeabi_ for the Arm
* standard library causes a crash when there are no global constructors.
* To avoid this do not override __cpp_initialize__aeabi_ with the super$$
* sub$$ mechanism for the Arm standard library. The uARM library is not
* effected by this problem.
*/
/*
* mbed entry point for the ARM standard toolchain
*
* Override the ARM standard library function __rt_entry to run code earlier in
* the boot sequence. This is after scatter loading has taken place but before
* the C library has been initialized.
*/
void __rt_entry(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
/* Interrupt stack - reserve space at the end of the free block */
mbed_stack_isr_size = ISR_STACK_SIZE < free_size ? ISR_STACK_SIZE : free_size;
mbed_stack_isr_start = free_start + free_size - mbed_stack_isr_size;
free_size -= mbed_stack_isr_size;
#endif
/* Heap - everything else */
mbed_heap_size = free_size;
mbed_heap_start = free_start;
mbed_init();
_platform_post_stackheap_init();
mbed_rtos_start();
}
void mbed_toolchain_init()
{
/* Run the C++ global object constructors */
__rt_lib_init((unsigned)mbed_heap_start, (unsigned)(mbed_heap_start + mbed_heap_size));
}
/* Move all code here from RTX code base (rtx_lib.c) and do some modifications:
*
* 1. _mutex_initialize/_mutex_free are re-implemented to meet Mbed.
* 2. All _mutex_* functions are declared with '__USED' to avoid excluded by linker.
*/
#if defined(RTX_NO_MULTITHREAD_CLIB)
/* The single memory model is checking for stack collision at run time, verifying
that the heap pointer is underneath the stack pointer.
With the RTOS there is not only one stack above the heap, there are multiple
stacks and some of them are underneath the heap pointer.
*/
#if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
__asm(".global __use_two_region_memory\n\t");
__asm(".global __use_no_semihosting\n\t");
#else
#pragma import(__use_two_region_memory)
#endif
#define LIBSPACE_SIZE 96
//lint -esym(714,__user_perthread_libspace,_mutex_*) "Referenced by C library"
//lint -esym(765,__user_perthread_libspace,_mutex_*) "Global scope"
//lint -esym(9003, os_libspace*) "variables 'os_libspace*' defined at module scope"
// Memory for libspace
static uint32_t os_libspace[OS_THREAD_LIBSPACE_NUM+1][LIBSPACE_SIZE/4] \
__attribute__((section(".bss.os.libspace")));
// Thread IDs for libspace
static osThreadId_t os_libspace_id[OS_THREAD_LIBSPACE_NUM] \
__attribute__((section(".bss.os.libspace")));
// Check if Kernel has been started
static uint32_t os_kernel_is_active (void) {
static uint8_t os_kernel_active = 0U;
if (os_kernel_active == 0U) {
if (osKernelGetState() > osKernelReady) {
os_kernel_active = 1U;
}
}
return (uint32_t)os_kernel_active;
}
// Provide libspace for current thread
void *__user_perthread_libspace (void) {
osThreadId_t id;
uint32_t n;
if (os_kernel_is_active() != 0U) {
id = osThreadGetId();
for (n = 0U; n < (uint32_t)OS_THREAD_LIBSPACE_NUM; n++) {
if (os_libspace_id[n] == NULL) {
os_libspace_id[n] = id;
}
if (os_libspace_id[n] == id) {
break;
}
}
if (n == (uint32_t)OS_THREAD_LIBSPACE_NUM) {
(void)osRtxErrorNotify(osRtxErrorClibSpace, id);
}
} else {
n = OS_THREAD_LIBSPACE_NUM;
}
//lint -e{9087} "cast between pointers to different object types"
return (void *)&os_libspace[n][0];
}
/* ARM toolchain requires dynamically created mutexes to enforce thread safety. There's
up to 8 static mutexes, protecting atexit, signalinit, stdin, stdout, stderr, stream_list,
fp_trap_init and the heap. Additionally for each call to fopen one extra mutex will be
created.
mbed OS provides a RTX pool for 8 mutexes, to satisfy the static requirements. All
additional mutexes will be allocated on the heap. We can't use the heap allocation for
all the required mutexes, as the heap operations also require a mutex. We don't need to
worry about freeing the allocated memory as library mutexes are only freed when the
application finishes executing.
*/
typedef void *mutex;
#define OS_MUTEX_STATIC_NUM 8
mutex _static_mutexes[OS_MUTEX_STATIC_NUM] = {NULL};
mbed_rtos_storage_mutex_t _static_mutexes_mem[OS_MUTEX_STATIC_NUM] = {NULL};
//lint -save "Function prototypes defined in C library"
//lint -e970 "Use of 'int' outside of a typedef"
//lint -e818 "Pointer 'm' could be declared as pointing to const"
/* Initialize mutex */
__USED int _mutex_initialize(mutex *m)
{
osMutexAttr_t attr;
memset(&attr, 0, sizeof(attr));
attr.name = "ARM toolchain mutex";
attr.attr_bits = osMutexRecursive | osMutexPrioInherit | osMutexRobust;
mutex *slot = NULL;
core_util_critical_section_enter();
for (int i = 0; i < OS_MUTEX_STATIC_NUM; i++) {
if (_static_mutexes[i] == NULL) {
_static_mutexes[i] = (mutex)-1; // dummy value to reserve slot
slot = &_static_mutexes[i];
//Use the static attrs
attr.cb_size = sizeof(mbed_rtos_storage_mutex_t);
attr.cb_mem = &_static_mutexes_mem[i];
break;
}
}
core_util_critical_section_exit();
if (slot != NULL) {
*m = osMutexNew(&attr);
*slot = *m;
if (*m != NULL) {
return 1;
}
}
/* Mutex pool exhausted, try using HEAP */
attr.cb_size = sizeof(mbed_rtos_storage_mutex_t);
attr.cb_mem = (void*)malloc(attr.cb_size);
if (attr.cb_mem == NULL) {
osRtxErrorNotify(osRtxErrorClibSpace, m);
return 0;
}
*m = osMutexNew(&attr);
if (*m == NULL) {
osRtxErrorNotify(osRtxErrorClibMutex, m);
return 0;
}
return 1;
}
/* Acquire mutex */
__USED void _mutex_acquire(mutex *m) {
if (os_kernel_is_active() != 0U) {
(void)osMutexAcquire(*m, osWaitForever);
}
}
/* Release mutex */
__USED void _mutex_release(mutex *m) {
if (os_kernel_is_active() != 0U) {
(void)osMutexRelease(*m);
}
}
/* Free mutex */
__USED void _mutex_free(mutex *m) {
mutex *slot = NULL;
core_util_critical_section_enter();
for (int i = 0; i < OS_MUTEX_STATIC_NUM; i++) {
if (_static_mutexes[i] == *m) {
slot = &_static_mutexes[i];
break;
}
}
core_util_critical_section_exit();
osMutexDelete(*m);
// if no slot reserved for mutex, must have been dynamically allocated
if (!slot) {
free(m);
} else {
*slot = NULL;
}
}
#endif /* RTX_NO_MULTITHREAD_CLIB */

View File

@ -0,0 +1,115 @@
/* mbed Microcontroller Library
* Copyright (c) 2018-2018 ARM Limited
*
* 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 "cmsis.h"
#include "mbed_toolchain.h"
#include "mbed_boot.h"
#include "mbed_rtos_storage.h"
#include "cmsis_os2.h"
static osMutexId_t malloc_mutex_id;
static mbed_rtos_storage_mutex_t malloc_mutex_obj;
static osMutexAttr_t malloc_mutex_attr;
static osMutexId_t env_mutex_id;
static mbed_rtos_storage_mutex_t env_mutex_obj;
static osMutexAttr_t env_mutex_attr;
#if !defined(HEAP_START)
/* Defined by linker script */
extern uint32_t __end__[];
#define HEAP_START ((unsigned char*)__end__)
#define HEAP_SIZE ((uint32_t)((uint32_t)INITIAL_SP - (uint32_t)HEAP_START))
#endif
extern void __libc_init_array (void);
/*
* mbed entry point for the GCC toolchain
*
* Override gcc boot hook software_init_hook to run code before main.
*/
void software_init_hook(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
/* Interrupt stack - reserve space at the end of the free block */
mbed_stack_isr_size = ISR_STACK_SIZE < free_size ? ISR_STACK_SIZE : free_size;
mbed_stack_isr_start = free_start + free_size - mbed_stack_isr_size;
free_size -= mbed_stack_isr_size;
#endif
/* Heap - everything else */
mbed_heap_size = free_size;
mbed_heap_start = free_start;
mbed_init();
mbed_rtos_start();
}
void mbed_toolchain_init()
{
malloc_mutex_attr.name = "malloc_mutex";
malloc_mutex_attr.attr_bits = osMutexRecursive | osMutexPrioInherit | osMutexRobust;
malloc_mutex_attr.cb_size = sizeof(malloc_mutex_obj);
malloc_mutex_attr.cb_mem = &malloc_mutex_obj;
malloc_mutex_id = osMutexNew(&malloc_mutex_attr);
env_mutex_attr.name = "env_mutex";
env_mutex_attr.attr_bits = osMutexRecursive | osMutexPrioInherit | osMutexRobust;
env_mutex_attr.cb_size = sizeof(env_mutex_obj);
env_mutex_attr.cb_mem = &env_mutex_obj;
env_mutex_id = osMutexNew(&env_mutex_attr);
/* Run the C++ global object constructors */
__libc_init_array();
}
extern int __real_main(void);
int __wrap_main(void) {
/* For backwards compatibility */
return __real_main();
}
/* Opaque declaration of _reent structure */
struct _reent;
void __rtos_malloc_lock( struct _reent *_r )
{
osMutexAcquire(malloc_mutex_id, osWaitForever);
}
void __rtos_malloc_unlock( struct _reent *_r )
{
osMutexRelease(malloc_mutex_id);
}
void __rtos_env_lock( struct _reent *_r )
{
osMutexAcquire(env_mutex_id, osWaitForever);
}
void __rtos_env_unlock( struct _reent *_r )
{
osMutexRelease(env_mutex_id);
}

View File

@ -0,0 +1,173 @@
/* mbed Microcontroller Library
* Copyright (c) 2018-2018 ARM Limited
*
* 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 "cmsis.h"
#include "mbed_error.h"
#include "mbed_boot.h"
#if defined(__IAR_SYSTEMS_ICC__ ) && (__VER__ >= 8000000)
#include <DLib_Threads.h>
#endif
#include "mbed_rtos_storage.h"
#include "cmsis_os2.h"
/* Defined by linker script */
#pragma section="CSTACK"
#pragma section="HEAP"
extern void* __vector_table;
extern int __low_level_init(void);
extern void __iar_data_init3(void);
extern __weak void __iar_init_core(void);
extern __weak void __iar_init_vfp(void);
extern void __iar_dynamic_initialization(void);
/*
* mbed entry point for the IAR toolchain
*
* Override __iar_program_start to run code before main.
* This is the first function called after the low level
* target initialization, so RAM has not been setup yet.
*
* Details on what this function are supposed to do can
* be found by looking at the IAR source for this file.
*
* IAR source files for ARM instruction set:
* <IAR>\arm\src\lib\arm\cstartup.s
* <IAR>\arm\src\lib\arm\cmain.s
*
* IAR source files for THUMB instruction set:
* <IAR>\arm\src\lib\thumb\cmain.s
* <IAR>\arm\src\lib\thumb\cstartup_M.s
*/
#pragma required=__vector_table
void __iar_program_start( void )
{
/* the calls below are normally made in IAR cstartup */
__iar_init_core();
__iar_init_vfp();
/* the calls below are normally made in IAR cmain
*
* The function "__low_level_init" is a user overrideable hook
* that does nothing by default. Returning zero means that
* ram initialization should be skipped. Skipping ram initialization
* is not allowed by mbed.
*
* The function "__iar_data_init3" is an IAR function which
* initializes ram.
*
*/
__low_level_init();
__iar_data_init3();
/* mbed specific code */
mbed_heap_start = (unsigned char*)__section_begin("HEAP");
mbed_heap_size = (uint32_t)__section_size("HEAP");
mbed_stack_isr_start = (unsigned char*)__section_begin("CSTACK");
mbed_stack_isr_size = (uint32_t)__section_size("CSTACK");
mbed_init();
mbed_rtos_start();
}
void mbed_toolchain_init(void)
{
#if defined(__IAR_SYSTEMS_ICC__ ) && (__VER__ >= 8000000)
__iar_Initlocks();
#endif
/* Run the C++ global object constructors */
__iar_dynamic_initialization();
}
/* Thread safety */
static osMutexId_t std_mutex_id_sys[_MAX_LOCK] = {0};
static mbed_rtos_storage_mutex_t std_mutex_sys[_MAX_LOCK] = {0};
#define _FOPEN_MAX 10
static osMutexId_t std_mutex_id_file[_FOPEN_MAX] = {0};
static mbed_rtos_storage_mutex_t std_mutex_file[_FOPEN_MAX] = {0};
void __iar_system_Mtxinit(__iar_Rmtx *mutex) /* Initialize a system lock */
{
osMutexAttr_t attr;
uint32_t index;
for (index = 0; index < _MAX_LOCK; index++) {
if (0 == std_mutex_id_sys[index]) {
attr.name = "system_mutex";
attr.cb_mem = &std_mutex_sys[index];
attr.cb_size = sizeof(std_mutex_sys[index]);
attr.attr_bits = osMutexRecursive | osMutexPrioInherit | osMutexRobust;
std_mutex_id_sys[index] = osMutexNew(&attr);
*mutex = (__iar_Rmtx*)&std_mutex_id_sys[index];
return;
}
}
/* This should never happen */
error("Not enough mutexes\n");
}
void __iar_system_Mtxdst(__iar_Rmtx *mutex) /* Destroy a system lock */
{
osMutexDelete(*(osMutexId_t*)*mutex);
*mutex = 0;
}
void __iar_system_Mtxlock(__iar_Rmtx *mutex) /* Lock a system lock */
{
osMutexAcquire(*(osMutexId_t*)*mutex, osWaitForever);
}
void __iar_system_Mtxunlock(__iar_Rmtx *mutex) /* Unlock a system lock */
{
osMutexRelease(*(osMutexId_t*)*mutex);
}
void __iar_file_Mtxinit(__iar_Rmtx *mutex) /* Initialize a file lock */
{
osMutexAttr_t attr;
uint32_t index;
for (index = 0; index < _FOPEN_MAX; index++) {
if (0 == std_mutex_id_file[index]) {
attr.name = "file_mutex";
attr.cb_mem = &std_mutex_file[index];
attr.cb_size = sizeof(std_mutex_file[index]);
attr.attr_bits = osMutexRecursive | osMutexPrioInherit | osMutexRobust;
std_mutex_id_file[index] = osMutexNew(&attr);
*mutex = (__iar_Rmtx*)&std_mutex_id_file[index];
return;
}
}
/* The variable _FOPEN_MAX needs to be increased */
error("Not enough mutexes\n");
}
void __iar_file_Mtxdst(__iar_Rmtx *mutex) /* Destroy a file lock */
{
osMutexDelete(*(osMutexId_t*)*mutex);
*mutex = 0;
}
void __iar_file_Mtxlock(__iar_Rmtx *mutex) /* Lock a file lock */
{
osMutexAcquire(*(osMutexId_t*)*mutex, osWaitForever);
}
void __iar_file_Mtxunlock(__iar_Rmtx *mutex) /* Unlock a file lock */
{
osMutexRelease(*(osMutexId_t*)*mutex);
}

View File

@ -28,96 +28,6 @@
* * mbed_main: User's code to be executed before main().
* * main: Standard application code.
*
* Detailed boot procedures:
*
* For ARMCC:
* ==========
*
* Reset (TARGET)
* -> SystemInit (TARGET)
* -> __main (LIBC)
* -> __rt_entry (MBED: rtos/mbed_boot.c)
* -> __user_setup_stackheap (LIBC)
* -> mbed_set_stack_heap (MBED: rtos/mbed_boot.c)
* -> mbed_cpy_nvic (MBED: rtos/mbed_boot.c)
* -> mbed_sdk_init (TARGET)
* -> _platform_post_stackheap_init (RTX)
* -> osKernelInitialize (RTX)
* -> mbed_start_main (MBED: rtos/mbed_boot.c)
* -> osThreadNew (RTX)
* -> pre_main(MBED: rtos/mbed_boot.c)
* -> __rt_lib_init (LIBC)
* -> $Sub$$main (MBED: rtos/mbed_boot.c)
* -> mbed_main (MBED: rtos/mbed_boot.c)
* -> main (APP)
* -> osKernelStart (RTX)
*
* In addition to the above, libc will use functions defined by RTX: __user_perthread_libspace, _mutex_initialize,
* _mutex_acquire, _mutex_release, _mutex_free for details consult: ARM C and C++ Libraries and Floating-Point
* Support User Guide.
*
* For MICROLIB:
* ==========
*
* Reset (TARGET)
* -> SystemInit (TARGET)
* -> __main (LIBC)
* -> _main_init (MBED: rtos/mbed_boot.c)
* -> mbed_set_stack_heap (MBED: rtos/mbed_boot.c)
* -> mbed_cpy_nvic (MBED: rtos/mbed_boot.c)
* -> mbed_sdk_init (TARGET)
* -> osKernelInitialize (RTX)
* -> mbed_start_main (MBED: rtos/mbed_boot.c)
* -> osThreadNew (RTX)
* -> pre_main(MBED: rtos/mbed_boot.c)
* -> __cpp_initialize__aeabi_ (LIBC)
* -> $Sub$$main (MBED: rtos/mbed_boot.c)
* -> mbed_main (MBED: rtos/mbed_boot.c)
* -> main (APP)
* -> osKernelStart (RTX)
*
* For GCC:
* ========
*
* Reset (TARGET)
* -> SystemInit (TARGET)
* -> __main (LIBC)
* -> software_init_hook (MBED: rtos/mbed_boot.c)
* -> mbed_set_stack_heap (MBED: rtos/mbed_boot.c)
* -> mbed_cpy_nvic (MBED: rtos/mbed_boot.c)
* -> mbed_sdk_init (TARGET)
* -> osKernelInitialize (RTX)
* -> mbed_start_main (MBED: rtos/mbed_boot.c)
* -> osThreadNew (RTX)
* -> pre_main(MBED: rtos/mbed_boot.c)
* -> __libc_init_array (LIBC)
* -> __wrap_main (MBED: rtos/mbed_boot.c)
* -> mbed_main (MBED: rtos/mbed_boot.c)
* -> __real_main (APP)
* -> osKernelStart (RTX)
*
* For IAR:
* ========
*
* Reset (TARGET)
* -> SystemInit (TARGET)
* -> __iar_program_start
* -> __iar_init_core
* -> __iar_init_core
* -> __iar_init_vfp
* -> __low_level_init
* -> __iar_data_init3
* -> mbed_cpy_nvic (MBED: rtos/mbed_boot.c)
* -> mbed_sdk_init (TARGET)
* -> mbed_set_stack_heap (MBED: rtos/mbed_boot.c)
* -> osKernelInitialize (RTX)
* -> mbed_start_main (MBED: rtos/mbed_boot.c)
* -> osThreadNew (RTX)
* -> pre_main(MBED: rtos/mbed_boot.c)
* -> __iar_dynamic_initialization
* -> main
* -> osKernelStart (RTX)
*
* Other notes:
*
* * In addition to the above, libc will use functions defined in mbed_boot.c: __rtos_malloc_lock/unlock,
@ -163,120 +73,43 @@
#include <stdlib.h>
#include "cmsis.h"
#include "mbed_rtx.h"
#include "mbed_rtos_storage.h"
#include "cmsis_os2.h"
#include "mbed_toolchain.h"
#include "mbed_error.h"
#include "mbed_critical.h"
#if defined(__IAR_SYSTEMS_ICC__ ) && (__VER__ >= 8000000)
#include <DLib_Threads.h>
#endif
/* Heap limits - only used if set */
extern unsigned char *mbed_heap_start;
extern uint32_t mbed_heap_size;
#include "mbed_boot.h"
int main(void);
static void mbed_cpy_nvic(void);
/* Stack limits */
unsigned char *mbed_stack_isr_start = 0;
uint32_t mbed_stack_isr_size = 0;
WEAK void mbed_main(void);
void pre_main (void);
void mbed_init(void)
{
mbed_cpy_nvic();
mbed_sdk_init();
mbed_rtos_init();
}
osThreadAttr_t _main_thread_attr;
void mbed_start(void)
{
mbed_toolchain_init();
mbed_main();
main();
}
/** The main thread's stack size can be configured by the application, if not explicitly specified it'll default to 4K */
#ifndef MBED_CONF_APP_MAIN_STACK_SIZE
#define MBED_CONF_APP_MAIN_STACK_SIZE 4096
#endif
MBED_ALIGN(8) char _main_stack[MBED_CONF_APP_MAIN_STACK_SIZE];
mbed_rtos_storage_thread_t _main_obj;
MBED_WEAK void mbed_sdk_init(void)
{
// Nothing by default
}
osMutexId_t singleton_mutex_id;
mbed_rtos_storage_mutex_t singleton_mutex_obj;
osMutexAttr_t singleton_mutex_attr;
MBED_WEAK void software_init_hook_rtos()
{
// Nothing by default
}
/*
* 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
#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
/* IAR - INITIAL_SP and HEAP_START ignored as described in Memory layout notes above
*/
#if !defined(__ICCARM__) && !defined(INITIAL_SP) && !defined(HEAP_START)
#error "no target defined"
#endif
/* Interrupt stack and heap always defined for IAR
* Main thread defined here
*/
#if defined(__ICCARM__)
#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) || (defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))
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)1024)
#endif
/*
* mbed_set_stack_heap purpose is to set the following variables:
* -mbed_heap_start
* -mbed_heap_size
* -mbed_stack_isr_start
* -mbed_stack_isr_size
*/
void mbed_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
/* Interrupt stack - reserve space at the end of the free block */
mbed_stack_isr_size = ISR_STACK_SIZE < free_size ? ISR_STACK_SIZE : free_size;
mbed_stack_isr_start = free_start + free_size - mbed_stack_isr_size;
free_size -= mbed_stack_isr_size;
#endif
/* Heap - everything else */
mbed_heap_size = free_size;
mbed_heap_start = free_start;
MBED_WEAK void mbed_main(void)
{
// Nothing by default
}
static void mbed_cpy_nvic(void)
@ -296,513 +129,3 @@ static void mbed_cpy_nvic(void)
#endif /* NVIC_RAM_VECTOR_ADDRESS */
#endif /* !defined(__CORTEX_M0) && !defined(__CORTEX_A9) */
}
/* mbed_main is a function that is called before main()
* mbed_sdk_init() is also a function that is called before main(), but unlike
* mbed_main(), it is not meant for user code, but for the SDK itself to perform
* initializations before main() is called.
*/
WEAK void mbed_main(void) {
}
/* This function can be implemented by the target to perform higher level target initialization, before the mbed OS or
* RTX is started.
*/
void mbed_sdk_init(void);
WEAK void mbed_sdk_init(void) {
}
void mbed_start_main(void)
{
_main_thread_attr.stack_mem = _main_stack;
_main_thread_attr.stack_size = sizeof(_main_stack);
_main_thread_attr.cb_size = sizeof(_main_obj);
_main_thread_attr.cb_mem = &_main_obj;
_main_thread_attr.priority = osPriorityNormal;
_main_thread_attr.name = "main_thread";
/* Allow non-secure main thread to call secure functions */
#if defined(DOMAIN_NS) && (DOMAIN_NS == 1U)
_main_thread_attr.tz_module = 1U;
#endif
osThreadId_t result = osThreadNew((osThreadFunc_t)pre_main, NULL, &_main_thread_attr);
if ((void *)result == NULL) {
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_INITIALIZATION_FAILED), "Pre main thread not created", &_main_thread_attr);
}
osKernelStart();
}
/******************** Toolchain specific code ********************/
#if defined (__CC_ARM) || (defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))
/* Common for both ARMC and MICROLIB */
int $Super$$main(void);
int $Sub$$main(void) {
mbed_main();
return $Super$$main();
}
#if defined (__MICROLIB) /******************** MICROLIB ********************/
int main(void);
void _main_init (void) __attribute__((section(".ARM.Collect$$$$000000FF")));
void $Super$$__cpp_initialize__aeabi_(void);
void _main_init (void) {
mbed_set_stack_heap();
mbed_cpy_nvic();
mbed_sdk_init();
osKernelInitialize();
mbed_start_main();
for (;;);
}
void $Sub$$__cpp_initialize__aeabi_(void)
{
/* This should invoke C++ initializers prior _main_init, we keep this empty and
* invoke them after _main_init, when the RTX is already initilized.
*/
}
void pre_main()
{
singleton_mutex_attr.name = "singleton_mutex";
singleton_mutex_attr.attr_bits = osMutexRecursive | osMutexPrioInherit | osMutexRobust;
singleton_mutex_attr.cb_size = sizeof(singleton_mutex_obj);
singleton_mutex_attr.cb_mem = &singleton_mutex_obj;
singleton_mutex_id = osMutexNew(&singleton_mutex_attr);
$Super$$__cpp_initialize__aeabi_();
main();
}
#else /******************** ARMC ********************/
#include <rt_misc.h>
extern __value_in_regs struct __argc_argv __rt_lib_init(unsigned heapbase, unsigned heaptop);
extern __value_in_regs struct __initial_stackheap __user_setup_stackheap(void);
extern void _platform_post_stackheap_init (void);
extern int main(int argc, char* argv[]);
void pre_main (void)
{
singleton_mutex_attr.name = "singleton_mutex";
singleton_mutex_attr.attr_bits = osMutexRecursive | osMutexPrioInherit | osMutexRobust;
singleton_mutex_attr.cb_size = sizeof(singleton_mutex_obj);
singleton_mutex_attr.cb_mem = &singleton_mutex_obj;
singleton_mutex_id = osMutexNew(&singleton_mutex_attr);
__rt_lib_init((unsigned)mbed_heap_start, (unsigned)(mbed_heap_start + mbed_heap_size));
main(0, NULL);
}
/* The single memory model is checking for stack collision at run time, verifing
that the heap pointer is underneath the stack pointer.
With the RTOS there is not only one stack above the heap, there are multiple
stacks and some of them are underneath the heap pointer.
*/
#if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
__asm(".global __use_two_region_memory\n\t");
__asm(".global __use_no_semihosting\n\t");
#else
#pragma import(__use_two_region_memory)
#endif
/* Called by the C library */
void __rt_entry (void) {
__user_setup_stackheap();
mbed_set_stack_heap();
mbed_cpy_nvic();
mbed_sdk_init();
_platform_post_stackheap_init();
mbed_start_main();
}
/* Move all code here from RTX code base (rtx_lib.c) and do some modifications:
*
* 1. _mutex_initialize/_mutex_free are re-implemented to meet Mbed.
* 2. All _mutex_* functions are declared with '__USED' to avoid excluded by linker.
*/
#if defined(RTX_NO_MULTITHREAD_CLIB)
#define LIBSPACE_SIZE 96
//lint -esym(714,__user_perthread_libspace,_mutex_*) "Referenced by C library"
//lint -esym(765,__user_perthread_libspace,_mutex_*) "Global scope"
//lint -esym(9003, os_libspace*) "variables 'os_libspace*' defined at module scope"
// Memory for libspace
static uint32_t os_libspace[OS_THREAD_LIBSPACE_NUM+1][LIBSPACE_SIZE/4] \
__attribute__((section(".bss.os.libspace")));
// Thread IDs for libspace
static osThreadId_t os_libspace_id[OS_THREAD_LIBSPACE_NUM] \
__attribute__((section(".bss.os.libspace")));
// Check if Kernel has been started
static uint32_t os_kernel_is_active (void) {
static uint8_t os_kernel_active = 0U;
if (os_kernel_active == 0U) {
if (osKernelGetState() > osKernelReady) {
os_kernel_active = 1U;
}
}
return (uint32_t)os_kernel_active;
}
// Provide libspace for current thread
void *__user_perthread_libspace (void) {
osThreadId_t id;
uint32_t n;
if (os_kernel_is_active() != 0U) {
id = osThreadGetId();
for (n = 0U; n < (uint32_t)OS_THREAD_LIBSPACE_NUM; n++) {
if (os_libspace_id[n] == NULL) {
os_libspace_id[n] = id;
}
if (os_libspace_id[n] == id) {
break;
}
}
if (n == (uint32_t)OS_THREAD_LIBSPACE_NUM) {
(void)osRtxErrorNotify(osRtxErrorClibSpace, id);
}
} else {
n = OS_THREAD_LIBSPACE_NUM;
}
//lint -e{9087} "cast between pointers to different object types"
return (void *)&os_libspace[n][0];
}
/* ARM toolchain requires dynamically created mutexes to enforce thread safety. There's
up to 8 static mutexes, protecting atexit, signalinit, stdin, stdout, stderr, stream_list,
fp_trap_init and the heap. Additionally for each call to fopen one extra mutex will be
created.
mbed OS provides a RTX pool for 8 mutexes, to satisfy the static requirements. All
additional mutexes will be allocated on the heap. We can't use the heap allocation for
all the required mutexes, as the heap operations also require a mutex. We don't need to
worry about freeing the allocated memory as library mutexes are only freed when the
application finishes executing.
*/
typedef void *mutex;
#define OS_MUTEX_STATIC_NUM 8
mutex _static_mutexes[OS_MUTEX_STATIC_NUM] = {NULL};
mbed_rtos_storage_mutex_t _static_mutexes_mem[OS_MUTEX_STATIC_NUM] = {NULL};
//lint -save "Function prototypes defined in C library"
//lint -e970 "Use of 'int' outside of a typedef"
//lint -e818 "Pointer 'm' could be declared as pointing to const"
/* Initialize mutex */
__USED int _mutex_initialize(mutex *m)
{
osMutexAttr_t attr;
memset(&attr, 0, sizeof(attr));
attr.name = "ARM toolchain mutex";
attr.attr_bits = osMutexRecursive | osMutexPrioInherit | osMutexRobust;
mutex *slot = NULL;
core_util_critical_section_enter();
for (int i = 0; i < OS_MUTEX_STATIC_NUM; i++) {
if (_static_mutexes[i] == NULL) {
_static_mutexes[i] = (mutex)-1; // dummy value to reserve slot
slot = &_static_mutexes[i];
//Use the static attrs
attr.cb_size = sizeof(mbed_rtos_storage_mutex_t);
attr.cb_mem = &_static_mutexes_mem[i];
break;
}
}
core_util_critical_section_exit();
if (slot != NULL) {
*m = osMutexNew(&attr);
*slot = *m;
if (*m != NULL) {
return 1;
}
}
/* Mutex pool exhausted, try using HEAP */
attr.cb_size = sizeof(mbed_rtos_storage_mutex_t);
attr.cb_mem = (void*)malloc(attr.cb_size);
if (attr.cb_mem == NULL) {
osRtxErrorNotify(osRtxErrorClibSpace, m);
return 0;
}
*m = osMutexNew(&attr);
if (*m == NULL) {
osRtxErrorNotify(osRtxErrorClibMutex, m);
return 0;
}
return 1;
}
/* Acquire mutex */
__USED void _mutex_acquire(mutex *m) {
if (os_kernel_is_active() != 0U) {
(void)osMutexAcquire(*m, osWaitForever);
}
}
/* Release mutex */
__USED void _mutex_release(mutex *m) {
if (os_kernel_is_active() != 0U) {
(void)osMutexRelease(*m);
}
}
/* Free mutex */
__USED void _mutex_free(mutex *m) {
mutex *slot = NULL;
core_util_critical_section_enter();
for (int i = 0; i < OS_MUTEX_STATIC_NUM; i++) {
if (_static_mutexes[i] == *m) {
slot = &_static_mutexes[i];
break;
}
}
core_util_critical_section_exit();
osMutexDelete(*m);
// if no slot reserved for mutex, must have been dynamically allocated
if (!slot) {
free(m);
} else {
*slot = NULL;
}
}
#endif /* RTX_NO_MULTITHREAD_CLIB */
#endif /* ARMC */
#elif defined (__GNUC__) /******************** GCC ********************/
extern int main(int argc, char* argv[]);
extern void __libc_init_array (void);
extern int __real_main(void);
osMutexId_t malloc_mutex_id;
mbed_rtos_storage_mutex_t malloc_mutex_obj;
osMutexAttr_t malloc_mutex_attr;
osMutexId_t env_mutex_id;
mbed_rtos_storage_mutex_t env_mutex_obj;
osMutexAttr_t env_mutex_attr;
int __wrap_main(void) {
mbed_main();
return __real_main();
}
void pre_main(void)
{
singleton_mutex_attr.name = "singleton_mutex";
singleton_mutex_attr.attr_bits = osMutexRecursive | osMutexPrioInherit | osMutexRobust;
singleton_mutex_attr.cb_size = sizeof(singleton_mutex_obj);
singleton_mutex_attr.cb_mem = &singleton_mutex_obj;
singleton_mutex_id = osMutexNew(&singleton_mutex_attr);
malloc_mutex_attr.name = "malloc_mutex";
malloc_mutex_attr.attr_bits = osMutexRecursive | osMutexPrioInherit | osMutexRobust;
malloc_mutex_attr.cb_size = sizeof(malloc_mutex_obj);
malloc_mutex_attr.cb_mem = &malloc_mutex_obj;
malloc_mutex_id = osMutexNew(&malloc_mutex_attr);
env_mutex_attr.name = "env_mutex";
env_mutex_attr.attr_bits = osMutexRecursive | osMutexPrioInherit | osMutexRobust;
env_mutex_attr.cb_size = sizeof(env_mutex_obj);
env_mutex_attr.cb_mem = &env_mutex_obj;
env_mutex_id = osMutexNew(&env_mutex_attr);
__libc_init_array();
main(0, NULL);
}
void software_init_hook(void)
{
mbed_set_stack_heap();
mbed_cpy_nvic();
mbed_sdk_init();
osKernelInitialize();
mbed_start_main();
}
/* Opaque declaration of _reent structure */
struct _reent;
void __rtos_malloc_lock( struct _reent *_r )
{
osMutexAcquire(malloc_mutex_id, osWaitForever);
}
void __rtos_malloc_unlock( struct _reent *_r )
{
osMutexRelease(malloc_mutex_id);
}
void __rtos_env_lock( struct _reent *_r )
{
osMutexAcquire(env_mutex_id, osWaitForever);
}
void __rtos_env_unlock( struct _reent *_r )
{
osMutexRelease(env_mutex_id);
}
#endif
#if defined(__ICCARM__) /******************** IAR ********************/
extern void* __vector_table;
extern int __low_level_init(void);
extern void __iar_data_init3(void);
extern __weak void __iar_init_core( void );
extern __weak void __iar_init_vfp( void );
extern void __iar_dynamic_initialization(void);
extern void mbed_sdk_init(void);
extern int main(void);
extern void exit(int arg);
static uint8_t low_level_init_needed;
void pre_main(void)
{
singleton_mutex_attr.name = "singleton_mutex";
singleton_mutex_attr.attr_bits = osMutexRecursive | osMutexPrioInherit | osMutexRobust;
singleton_mutex_attr.cb_size = sizeof(singleton_mutex_obj);
singleton_mutex_attr.cb_mem = &singleton_mutex_obj;
singleton_mutex_id = osMutexNew(&singleton_mutex_attr);
#if defined(__IAR_SYSTEMS_ICC__ ) && (__VER__ >= 8000000)
__iar_Initlocks();
#endif
if (low_level_init_needed) {
__iar_dynamic_initialization();
}
mbed_main();
main();
}
#pragma required=__vector_table
void __iar_program_start( void )
{
__iar_init_core();
__iar_init_vfp();
uint8_t low_level_init_needed_local;
low_level_init_needed_local = __low_level_init();
if (low_level_init_needed_local) {
__iar_data_init3();
mbed_cpy_nvic();
mbed_sdk_init();
}
mbed_set_stack_heap();
/* Store in a global variable after RAM has been initialized */
low_level_init_needed = low_level_init_needed_local;
osKernelInitialize();
mbed_start_main();
}
/* Thread safety */
static osMutexId_t std_mutex_id_sys[_MAX_LOCK] = {0};
static mbed_rtos_storage_mutex_t std_mutex_sys[_MAX_LOCK] = {0};
#define _FOPEN_MAX 10
static osMutexId_t std_mutex_id_file[_FOPEN_MAX] = {0};
static mbed_rtos_storage_mutex_t std_mutex_file[_FOPEN_MAX] = {0};
void __iar_system_Mtxinit(__iar_Rmtx *mutex) /* Initialize a system lock */
{
osMutexAttr_t attr;
uint32_t index;
for (index = 0; index < _MAX_LOCK; index++) {
if (0 == std_mutex_id_sys[index]) {
attr.name = "system_mutex";
attr.cb_mem = &std_mutex_sys[index];
attr.cb_size = sizeof(std_mutex_sys[index]);
attr.attr_bits = osMutexRecursive | osMutexPrioInherit | osMutexRobust;
std_mutex_id_sys[index] = osMutexNew(&attr);
*mutex = (__iar_Rmtx*)&std_mutex_id_sys[index];
return;
}
}
/* This should never happen */
error("Not enough mutexes\n");
}
void __iar_system_Mtxdst(__iar_Rmtx *mutex) /* Destroy a system lock */
{
osMutexDelete(*(osMutexId_t*)*mutex);
*mutex = 0;
}
void __iar_system_Mtxlock(__iar_Rmtx *mutex) /* Lock a system lock */
{
osMutexAcquire(*(osMutexId_t*)*mutex, osWaitForever);
}
void __iar_system_Mtxunlock(__iar_Rmtx *mutex) /* Unlock a system lock */
{
osMutexRelease(*(osMutexId_t*)*mutex);
}
void __iar_file_Mtxinit(__iar_Rmtx *mutex) /* Initialize a file lock */
{
osMutexAttr_t attr;
uint32_t index;
for (index = 0; index < _FOPEN_MAX; index++) {
if (0 == std_mutex_id_file[index]) {
attr.name = "file_mutex";
attr.cb_mem = &std_mutex_file[index];
attr.cb_size = sizeof(std_mutex_file[index]);
attr.attr_bits = osMutexRecursive | osMutexPrioInherit | osMutexRobust;
std_mutex_id_file[index] = osMutexNew(&attr);
*mutex = (__iar_Rmtx*)&std_mutex_id_file[index];
return;
}
}
/* The variable _FOPEN_MAX needs to be increased */
error("Not enough mutexes\n");
}
void __iar_file_Mtxdst(__iar_Rmtx *mutex) /* Destroy a file lock */
{
osMutexDelete(*(osMutexId_t*)*mutex);
*mutex = 0;
}
void __iar_file_Mtxlock(__iar_Rmtx *mutex) /* Lock a file lock */
{
osMutexAcquire(*(osMutexId_t*)*mutex, osWaitForever);
}
void __iar_file_Mtxunlock(__iar_Rmtx *mutex) /* Unlock a file lock */
{
osMutexRelease(*(osMutexId_t*)*mutex);
}
#endif

View File

@ -0,0 +1,171 @@
/* mbed Microcontroller Library
* Copyright (c) 2018-2018 ARM Limited
*
* 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.
*/
#ifndef MBED_BOOT_H
#define MBED_BOOT_H
#include "mbed_toolchain.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "mbed_rtx.h"
/**
* \defgroup boot Boot sequence
* Boot sequence overview
*
* 1. Setup target
* - Configure clocks
* - Configure watchdog (if applicable)
* - Turn on RAM (if applicable)
* - Jump to setup toolchain
* 2. Setup toolchain
* - Initialize RAM
* - Initialize standard library
* - Call mbed_init
* - jump to start rtos
* 3. Start RTOS
* - Create main thread
* - Start scheduler
* - main thread calls start mbed
* 4. Start mbed
* - Call mbed_main
* - Call main
*
* @{
*/
/* Define stack sizes if they haven't been set already */
#if !defined(ISR_STACK_SIZE)
#define ISR_STACK_SIZE ((uint32_t)1024)
#endif
/* Heap limits - only used if set */
extern unsigned char *mbed_heap_start;
extern uint32_t mbed_heap_size;
/* Stack limits */
extern unsigned char *mbed_stack_isr_start;
extern uint32_t mbed_stack_isr_size;
/**
* Perform low level init of mbed
*
* The toolchain calls this function as part of the boot
* sequence. This function does the following:
* - Sets up NVIC so interrupts can be used
* - Calls into the vendor SDK so it can be used
* - Initializes the RTOS so it can be used
*
* Preconditions:
* - Target is initialized
* - Ram is initialized
* - value set for mbed_heap_start
* - value set for mbed_heap_size
* - value set for mbed_stack_isr_start
* - value set for mbed_stack_isr_size
*
* The following events must not have happened yet:
* - global constructors must not be called yet
*
*/
void mbed_init(void);
/**
* Start the main mbed application
*
* This is the last stage of the boot sequence. This function must be
* called only after the RTOS has been fully initialized.
* This function does the following:
* - Initialize the toolchain
* - Run mbed_main
* - Run main
*
* Preconditions:
* - The RTOS has been started by a call to mbed_rtos_start
*
*/
void mbed_start(void);
/**
* Perform low level initialization of the RTOS
*
* Set the RTOS to a known state but don't start the scheduler. After
* the RTOS has been initialized it is safe to create RTOS primitives
* for file locks or other purposes.
*
* Preconditions:
* - Ram is initialized
* - NVIC is setup
* - Vendor SDK must be initialized by a call to mbed_sdk_init
*/
void mbed_rtos_init(void);
/**
* Start the RTOS
*
* Start the RTOS scheduler and call mbed_start on the
* main thread. This function does not return.
*
* Preconditions:
* - RTOS has been initialized by a call to mbed_rtos_init
*/
MBED_NORETURN void mbed_rtos_start(void);
/**
* Perform toolchain specific initialization
*
* Initialize locks if this has not been done already
* and call global C++ constructors.
*
* Preconditions:
* - The RTOS has been started by a call to mbed_rtos_start
*/
void mbed_toolchain_init(void);
/**
* SDK hook for running code before ctors or OS
*
* This is a weak function which can be overridden by a target's
* SDK to allow code to run after ram is initialized but before
* the OS has been started or constructors have run.
*
* Preconditions:
* - Ram is initialized
* - NVIC is setup
*/
void mbed_sdk_init(void);
/**
* Application hook for running code before main
*
* This is a weak function which can be overridden by an application
* to allow code to run before main is called.
*
* Preconditions:
* - The RTOS has been started by a call to mbed_rtos_start
* - The toolchain has been initialized by a call to mbed_toolchain_init
*/
void mbed_main(void);
/**@}*/
#ifdef __cplusplus
}
#endif
#endif /* MBED_BOOT_H */

View File

@ -0,0 +1,72 @@
/* mbed Microcontroller Library
* Copyright (c) 2018-2018 ARM Limited
*
* 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 "cmsis.h"
#include "mbed_rtx.h"
#include "mbed_rtos_storage.h"
#include "cmsis_os2.h"
#include "mbed_toolchain.h"
#include "mbed_error.h"
#include "mbed_critical.h"
#include "mbed_boot.h"
osThreadAttr_t _main_thread_attr;
/** The main thread's stack size can be configured by the application, if not explicitly specified it'll default to 4K */
#ifndef MBED_CONF_APP_MAIN_STACK_SIZE
#define MBED_CONF_APP_MAIN_STACK_SIZE 4096
#endif
MBED_ALIGN(8) char _main_stack[MBED_CONF_APP_MAIN_STACK_SIZE];
mbed_rtos_storage_thread_t _main_obj;
osMutexId_t singleton_mutex_id;
mbed_rtos_storage_mutex_t singleton_mutex_obj;
osMutexAttr_t singleton_mutex_attr;
void mbed_rtos_init()
{
osKernelInitialize();
}
MBED_NORETURN void mbed_rtos_start()
{
singleton_mutex_attr.name = "singleton_mutex";
singleton_mutex_attr.attr_bits = osMutexRecursive | osMutexPrioInherit | osMutexRobust;
singleton_mutex_attr.cb_size = sizeof(singleton_mutex_obj);
singleton_mutex_attr.cb_mem = &singleton_mutex_obj;
_main_thread_attr.stack_mem = _main_stack;
_main_thread_attr.stack_size = sizeof(_main_stack);
_main_thread_attr.cb_size = sizeof(_main_obj);
_main_thread_attr.cb_mem = &_main_obj;
_main_thread_attr.priority = osPriorityNormal;
_main_thread_attr.name = "main_thread";
/* Allow non-secure main thread to call secure functions */
#if defined(DOMAIN_NS) && (DOMAIN_NS == 1U)
_main_thread_attr.tz_module = 1U;
#endif
singleton_mutex_id = osMutexNew(&singleton_mutex_attr);
osThreadId_t result = osThreadNew((osThreadFunc_t)mbed_start, NULL, &_main_thread_attr);
if ((void *)result == NULL) {
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_INITIALIZATION_FAILED), "Pre main thread not created", &_main_thread_attr);
}
osKernelStart();
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_INITIALIZATION_FAILED), "Failed to start RTOS");
while (1); // Code should never get here
}