µOS++ IIIe / CMSIS++ / POSIX++ Reference  v6.3.11
“Perfekt ist nicht gut genug”
The third edition of µOS++ and CMSIS++, a proposal for the next generation CMSIS, written in C++.
startup.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the µOS++ distribution.
3  * (https://github.com/micro-os-plus)
4  * Copyright (c) 2015 Liviu Ionescu.
5  *
6  * Permission is hereby granted, free of charge, to any person
7  * obtaining a copy of this software and associated documentation
8  * files (the "Software"), to deal in the Software without
9  * restriction, including without limitation the rights to use,
10  * copy, modify, merge, publish, distribute, sublicense, and/or
11  * sell copies of the Software, and to permit persons to whom
12  * the Software is furnished to do so, subject to the following
13  * conditions:
14  *
15  * The above copyright notice and this permission notice shall be
16  * included in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25  * OTHER DEALINGS IN THE SOFTWARE.
26  */
27 
28 #if defined(__ARM_EABI__)
29 
30 // ----------------------------------------------------------------------------
31 
32 #include <cmsis-plus/rtos/os.h>
33 
34 //#include <cmsis-plus/os-app-config.h>
35 //#include <cmsis-plus/rtos/port/os-c-decls.h>
36 //#include <cmsis-plus/rtos/os-hooks.h>
37 
38 #include <cmsis-plus/diag/trace.h>
39 
40 #include <cmsis_device.h>
41 
42 #include <stdint.h>
43 #include <stdlib.h>
44 #include <sys/types.h>
45 
46 // ----------------------------------------------------------------------------
47 // This file defines the startup code for a portable embedded
48 // C/C++ application, built with newlib.
49 //
50 // Control reaches here from the reset handler via jump or call.
51 //
52 // The actual steps performed by _start are:
53 // - copy the initialised data region(s)
54 // - clear the BSS region(s)
55 // - initialise the system
56 // - run the preinit/init array (for the C++ static constructors)
57 // - initialise the arc/argv
58 // - branch to main()
59 // - run the fini array (for the C++ static destructors)
60 // - call _exit(), directly or via exit()
61 //
62 // If OS_INCLUDE_STARTUP_INIT_MULTIPLE_RAM_SECTIONS is defined, the
63 // code is capable of initialising multiple regions.
64 //
65 // The normal configuration is standalone, with all support
66 // functions implemented locally.
67 //
68 // For this to be called, the project linker must be configured without
69 // the startup sequence (-nostartfiles).
70 // ----------------------------------------------------------------------------
71 
72 #if !defined(OS_INCLUDE_STARTUP_GUARD_CHECKS)
73 #define OS_BOOL_STARTUP_GUARD_CHECKS (true)
74 #endif
75 
76 // ----------------------------------------------------------------------------
77 
78 #if !defined(OS_INCLUDE_STARTUP_INIT_MULTIPLE_RAM_SECTIONS)
79 // Begin address for the initialisation values of the .data section.
80 // defined in linker script
81 extern unsigned int _sidata;
82 // Begin address for the .data section; defined in linker script
83 extern unsigned int _sdata;
84 // End address for the .data section; defined in linker script
85 extern unsigned int _edata;
86 
87 // Begin address for the .bss section; defined in linker script
88 extern unsigned int __bss_start__;
89 // End address for the .bss section; defined in linker script
90 extern unsigned int __bss_end__;
91 #else
92 // The following symbols are constructs generated by the linker, indicating
93 // the location of various points in the "Memory regions initialisation arrays".
94 // These arrays are created by the linker via the managed linker script
95 // of each RW data mechanism. It contains the load address, execution address
96 // and length section and the execution and length of each BSS (zero
97 // initialised) section.
98 extern unsigned int __data_regions_array_start;
99 extern unsigned int __data_regions_array_end;
100 extern unsigned int __bss_regions_array_start;
101 extern unsigned int __bss_regions_array_end;
102 #endif
103 
104 extern unsigned int _Heap_Begin;
105 extern unsigned long int _Heap_Limit;
106 extern unsigned long int __stack;
107 
108 extern "C" int
109 main (int argc, char* argv[]);
110 
111 // ----------------------------------------------------------------------------
112 
113 // Forward declarations
114 
115 extern "C"
116 {
117 void
118 _start (void);
119 
120 static void
121 os_initialize_data (unsigned int* from, unsigned int* region_begin,
122  unsigned int* region_end);
123 
124 static void
125 os_initialize_bss (unsigned int* region_begin, unsigned int* region_end);
126 
127 static void
128 os_run_init_array (void);
129 
130 // Not static since it is called from exit()
131 void
132 os_run_fini_array (void);
133 }
134 
135 // ----------------------------------------------------------------------------
136 
137 inline __attribute__((always_inline))
138 void
139 os_initialize_data (unsigned int* from, unsigned int* region_begin,
140  unsigned int* region_end)
141 {
142  // Iterate and copy word by word.
143  // It is assumed that the pointers are word aligned.
144  unsigned int *p = region_begin;
145  while (p < region_end)
146  {
147  *p++ = *from++;
148  }
149 }
150 
151 inline __attribute__((always_inline))
152 void
153 os_initialize_bss (unsigned int* region_begin, unsigned int* region_end)
154 {
155  // Iterate and clear word by word.
156  // It is assumed that the pointers are word aligned.
157  unsigned int *p = region_begin;
158  while (p < region_end)
159  {
160  *p++ = 0;
161  }
162 }
163 
164 // These magic symbols are provided by the linker.
165 extern void
166 (*__preinit_array_start[]) (void) __attribute__((weak));
167 extern void
168 (*__preinit_array_end[]) (void) __attribute__((weak));
169 extern void
170 (*__init_array_start[]) (void) __attribute__((weak));
171 extern void
172 (*__init_array_end[]) (void) __attribute__((weak));
173 extern void
174 (*__fini_array_start[]) (void) __attribute__((weak));
175 extern void
176 (*__fini_array_end[]) (void) __attribute__((weak));
177 
178 // Iterate over all the preinit/init routines (mainly static constructors).
179 inline __attribute__((always_inline))
180 void
182 {
183  trace_printf ("%s()\n", __func__);
184 
186  for (int i = 0; i < count; i++)
187  {
188  __preinit_array_start[i] ();
189  }
190 
191  // If the application needs to run the code in the .init section,
192  // please use the startup files, since this requires the code in
193  // crti.o and crtn.o to add the function prologue/epilogue.
194  //_init(); // DO NOT ENABE THIS!
195 
197  for (int i = 0; i < count; i++)
198  {
199  __init_array_start[i] ();
200  }
201 }
202 
203 // Run all the cleanup routines (mainly static destructors).
204 void
206 {
207  trace_printf ("%s()\n", __func__);
208 
209  int count = __fini_array_end - __fini_array_start;
210  for (int i = count; i > 0; i--)
211  {
212  __fini_array_start[i - 1] ();
213  }
214 
215  // If the application needs to run the code in the .fini section,
216  // please use the startup files, since this requires the code in
217  // crti.o and crtn.o to add the function prologue/epilogue.
218  //_fini(); // DO NOT ENABLE THIS!
219 }
220 
221 #if defined(DEBUG) && (OS_BOOL_STARTUP_GUARD_CHECKS)
222 
223 // These definitions are used to check if the routines used to
224 // clear the BSS and to copy the initialised DATA perform correctly.
225 
226 #define BSS_GUARD_BAD_VALUE (0xCADEBABA)
227 
228 static uint32_t volatile __attribute__ ((section(".bss_begin")))
229 __bss_begin_guard;
230 static uint32_t volatile __attribute__ ((section(".bss_end")))
231 __bss_end_guard;
232 
233 #define DATA_GUARD_BAD_VALUE (0xCADEBABA)
234 #define DATA_BEGIN_GUARD_VALUE (0x12345678)
235 #define DATA_END_GUARD_VALUE (0x98765432)
236 
237 static uint32_t volatile __attribute__ ((section(".data_begin")))
238 __data_begin_guard = DATA_BEGIN_GUARD_VALUE;
239 
240 static uint32_t volatile __attribute__ ((section(".data_end")))
241 __data_end_guard = DATA_END_GUARD_VALUE;
242 
243 #endif // defined(DEBUG) && (OS_BOOL_STARTUP_GUARD_CHECKS)
244 
256 void
257 __attribute__ ((section(".after_vectors"),noreturn,weak))
258 _start (void)
259 {
260  // After Reset the Cortex-M processor is in Thread mode,
261  // priority is Privileged, and the Stack is set to Main.
262 
263  // --------------------------------------------------------------------------
264 
265  // Initialise hardware right after reset, to switch clock to higher
266  // frequency and have the rest of the initialisations run faster.
267  //
268  // Mandatory on platforms like Kinetis, which start with the watch dog
269  // enabled and require an early sequence to disable it.
270  //
271  // Also useful on platform with external RAM, that need to be
272  // initialised before filling the BSS section.
273 
275 
276  // Use Old Style DATA and BSS section initialisation,
277  // that will manage a single BSS sections.
278 
279 #if defined(DEBUG) && (OS_BOOL_STARTUP_GUARD_CHECKS)
280 
281  __data_begin_guard = DATA_GUARD_BAD_VALUE;
282  __data_end_guard = DATA_GUARD_BAD_VALUE;
283 
284 #endif
285 
286 #if !defined(OS_INCLUDE_STARTUP_INIT_MULTIPLE_RAM_SECTIONS)
287 
288  // Copy the DATA segment from Flash to RAM (inlined).
290 
291 #else
292 
293  // Copy the data sections from flash to SRAM.
294  for (unsigned int* p = &__data_regions_array_start;
295  p < &__data_regions_array_end;)
296  {
297  unsigned int* from = (unsigned int *) (*p++);
298  unsigned int* region_begin = (unsigned int *) (*p++);
299  unsigned int* region_end = (unsigned int *) (*p++);
300 
301  os_initialize_data (from, region_begin, region_end);
302  }
303 
304 #endif
305 
306 #if defined(DEBUG) && (OS_BOOL_STARTUP_GUARD_CHECKS)
307 
308  if ((__data_begin_guard != DATA_BEGIN_GUARD_VALUE)
309  || (__data_end_guard != DATA_END_GUARD_VALUE))
310  {
311  while (true)
312  {
313  __NOP ();
314  }
315  }
316 
317 #endif
318 
319 #if defined(DEBUG) && (OS_BOOL_STARTUP_GUARD_CHECKS)
320 
321  __bss_begin_guard = BSS_GUARD_BAD_VALUE;
322  __bss_end_guard = BSS_GUARD_BAD_VALUE;
323 
324 #endif
325 
326 #if !defined(OS_INCLUDE_STARTUP_INIT_MULTIPLE_RAM_SECTIONS)
327 
328  // Zero fill the BSS section (inlined).
330 
331 #else
332 
333  // Zero fill all bss segments
334  for (unsigned int *p = &__bss_regions_array_start;
335  p < &__bss_regions_array_end;)
336  {
337  unsigned int* region_begin = (unsigned int*) (*p++);
338  unsigned int* region_end = (unsigned int*) (*p++);
339  os_initialize_bss (region_begin, region_end);
340  }
341 
342 #endif
343 
344 #if defined(DEBUG) && (OS_BOOL_STARTUP_GUARD_CHECKS)
345 
346  if ((__bss_begin_guard != 0) || (__bss_end_guard != 0))
347  {
348  while (true)
349  {
350  __NOP ();
351  }
352  }
353 
354 #endif
355 
356  // Hook to continue the initialisations. Usually compute and store the
357  // clock frequency in the global CMSIS variable, cleared above.
359 
360  // Initialise the trace output device. From this moment on,
361  // trace_printf() calls are available (including in static constructors).
362  trace_initialize ();
363 
364  trace_printf ("Hardware initialised.\n");
365 
367  &_Heap_Begin, (size_t) ((char*) (&_Heap_Limit) - (char*) (&_Heap_Begin)));
368 
369  // Get the argc/argv (useful in semihosting configurations).
370  int argc;
371  char** argv;
372  os_startup_initialize_args (&argc, &argv);
373 
374  // Call the standard library initialisation (mandatory for C++ to
375  // execute the constructors for the static objects).
377 
378 #if defined(OS_HAS_INTERRUPTS_STACK)
379  os::rtos::interrupts::stack ()->set(&_Heap_Limit, (size_t) ((char*) (&__stack) - (char*) (&_Heap_Limit)));
380 #endif /* defined(OS_HAS_INTERRUPTS_STACK) */
381 
382  // Call the main entry point, and save the exit code.
383  int code = main (argc, argv);
384 
385  // Standard program termination;
386  // `atexit()` and C++ static destructors are executed.
387  exit (code);
388  /* NOTREACHED */
389 }
390 
391 // ----------------------------------------------------------------------------
392 
393 #if !defined(OS_USE_SEMIHOSTING_SYSCALLS)
394 
395 // Semihosting uses a more elaborate version of os_startup_initialize_args()
396 // to parse args received from host.
397 
398 #pragma GCC diagnostic push
399 #pragma GCC diagnostic ignored "-Wunused-parameter"
400 
401 // This is the standard default implementation for the routine to
402 // process args. It returns a single empty arg.
403 //
404 // For semihosting applications, this is redefined to get the real
405 // args from the debugger.
406 //
407 // The application can redefine it to fetch some args from a
408 // non-volatile memory.
409 
410 void __attribute__((weak))
411 os_startup_initialize_args (int* p_argc, char*** p_argv)
412  {
413  // By the time we reach this, the data and bss should have been initialised.
414 
415  // The strings pointed to by the argv array shall be modifiable by the
416  // program, and retain their last-stored values between program startup
417  // and program termination. (static, no const)
418  static char name[] = "";
419 
420  // The string pointed to by argv[0] represents the program name;
421  // argv[0][0] shall be the null character if the program name is not
422  // available from the host environment. argv[argc] shall be a null pointer.
423  // (static, no const)
424  static char* argv[2] =
425  { name, NULL};
426 
427  *p_argc = 1;
428  *p_argv = &argv[0];
429 
430  return;
431  }
432 
433 #pragma GCC diagnostic pop
434 
435 #endif /* !defined(OS_USE_SEMIHOSTING_SYSCALLS) */
436 
437 // ----------------------------------------------------------------------------
438 
439 #endif /* defined(__ARM_EABI__) */
440 
void(* __init_array_start[])(void)
void exit(int code)
Definition: exit.c:78
class thread::stack * stack(void)
Get the interrupts stack.
Definition: os-core.cpp:528
void(* __fini_array_start[])(void)
unsigned int __bss_start__
void(* __preinit_array_start[])(void)
void os_startup_initialize_args(int *p_argc, char ***p_argv)
Initialise arguments.
Definition: startup.cpp:411
void(* __fini_array_end[])(void)
void os_startup_initialize_hardware(void)
Initialise hardware.
void os_startup_initialize_hardware_early(void)
Initialise hardware early.
void set(stack::element_t *address, std::size_t size_bytes)
Set the stack address and size.
Definition: os-thread.h:2099
void(* __preinit_array_end[])(void)
void os_run_fini_array(void)
Definition: startup.cpp:205
void trace_initialize(void)
Definition: trace.cpp:165
int main(int argc, char *argv[])
Default implementation of main().
Definition: os-main.cpp:113
static void os_initialize_bss(unsigned int *region_begin, unsigned int *region_end)
Definition: startup.cpp:153
unsigned int _Heap_Begin
void(* __init_array_end[])(void)
unsigned int _edata
unsigned int _sdata
unsigned long int __stack
Single file CMSIS++ RTOS definitions.
int trace_printf(const char *format,...)
void _start(void)
The standard C application entry point.
Definition: startup.cpp:258
unsigned int _sidata
static void os_run_init_array(void)
Definition: startup.cpp:181
static void os_initialize_data(unsigned int *from, unsigned int *region_begin, unsigned int *region_end)
Definition: startup.cpp:139
void os_startup_initialize_free_store(void *heap_address, size_t heap_size_bytes)
Initialise free store.
unsigned long int _Heap_Limit
unsigned int __bss_end__