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