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