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