• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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