1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 // !!!WARNING!!!
16 //
17 // Some of the code in this file is run without static initialization expected
18 // by C/C++. Any accesses to statically initialized objects/variables before
19 // memory is initialized will result in undefined values and violates the C
20 // specification. Only code run after memory initialization is complete will be
21 // compliant and truly safe to run. In general, make early initialization code
22 // run AFTER memory initialization has completed unless it is ABSOLUTELY
23 // NECESSARY to modify the way memory is initialized.
24 //
25 // This file is similar to a traditional assembly startup file. It turns out
26 // that everything typically done in ARMv7-M assembly startup can be done
27 // straight from C code. This makes startup code easier to maintain, modify,
28 // and read.
29 //
30 // When execution begins due to SoC power-on (or the device is reset), three
31 // key things must happen to properly enter C++ execution context:
32 // 1. Static variables must be loaded from flash to RAM.
33 // 2. Zero-initialized variables must be zero-initialized.
34 // 3. Statically allocated objects must have their constructors run.
35 // The SoC doesn't inherently have a notion of how to do this, so this is
36 // handled in StaticInit();
37 //
38 // Following this, execution is handed over to pw_PreMainInit() to facilitate
39 // platform, project, or application pre-main initialization. When
40 // pw_PreMainInit() returns, main() is executed.
41 //
42 // The simple flow is as follows:
43 // 1. Power on
44 // 2. PC and SP set (from vector_table by SoC, or by bootloader)
45 // 3. pw_boot_Entry()
46 // 3.1. pw_boot_PreStaticMemoryInit();
47 // 3.2. Static-init memory (.data, .bss)
48 // 3.3. pw_boot_PreStaticConstructorInit();
49 // 3.4. Static C++ constructors
50 // 3.5. pw_boot_PreMainInit()
51 // 3.6. main()
52 // 3.7. pw_boot_PostMain()
53
54 #include <stdbool.h>
55 #include <stdint.h>
56 #include <string.h>
57
58 #include "pw_boot_armv7m/boot.h"
59 #include "pw_preprocessor/compiler.h"
60
61 // Extern symbols provided by linker script.
62 // These symbols tell us where various memory sections start and end.
63 extern uint8_t _pw_static_init_ram_start;
64 extern uint8_t _pw_static_init_ram_end;
65 extern uint8_t _pw_static_init_flash_start;
66 extern uint8_t _pw_zero_init_ram_start;
67 extern uint8_t _pw_zero_init_ram_end;
68
69 // Functions called as part of firmware initialization.
70 void __libc_init_array(void);
71
72 // WARNING: Be EXTREMELY careful when running code before this function
73 // completes. The context before this function violates the C spec
74 // (Section 6.7.8, paragraph 10 for example, which requires uninitialized static
75 // values to be zero-initialized).
StaticMemoryInit(void)76 void StaticMemoryInit(void) {
77 // Static-init RAM (load static values into ram, .data section init).
78 memcpy(&_pw_static_init_ram_start,
79 &_pw_static_init_flash_start,
80 &_pw_static_init_ram_end - &_pw_static_init_ram_start);
81
82 // Zero-init RAM (.bss section init).
83 memset(&_pw_zero_init_ram_start,
84 0,
85 &_pw_zero_init_ram_end - &_pw_zero_init_ram_start);
86 }
87
88 // WARNING: This code is run immediately upon boot, and performs initialization
89 // of RAM. Note that code running before this function finishes memory
90 // initialization will violate the C spec (Section 6.7.8, paragraph 10 for
91 // example, which requires uninitialized static values to be zero-initialized).
92 // Be EXTREMELY careful when running code before this function finishes RAM
93 // initialization.
94 //
95 // This function runs immediately at boot because it is at index 1 of the
96 // interrupt vector table.
pw_boot_Entry()97 void pw_boot_Entry() {
98 // Run any init that must be done before static init of RAM which preps the
99 // .data (static values not yet loaded into ram) and .bss sections (not yet
100 // zero-initialized).
101 pw_boot_PreStaticMemoryInit();
102
103 // Note that code running before this function finishes memory
104 // initialization will violate the C spec (Section 6.7.8, paragraph 10 for
105 // example, which requires uninitialized static values to be
106 // zero-initialized). Be EXTREMELY careful when running code before this
107 // function finishes static memory initialization.
108 StaticMemoryInit();
109
110 // Run any init that must be done before C++ static constructors.
111 pw_boot_PreStaticConstructorInit();
112
113 // Call static constructors.
114 __libc_init_array();
115
116 // This function is not provided by pw_boot_armv7m, a platform layer, project,
117 // or application is expected to implement it.
118 pw_boot_PreMainInit();
119
120 // Run main.
121 main();
122
123 // In case main() returns, invoke this hook.
124 pw_boot_PostMain();
125
126 PW_UNREACHABLE;
127 }
128