Armando Montanez | 7009566 | 2020-01-09 14:25:04 -0800 | [diff] [blame] | 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) |
Ewout van Bekkum | fff82ec | 2020-08-21 15:54:28 -0700 | [diff] [blame] | 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() |
Ewout van Bekkum | 738f42c | 2020-08-24 12:55:13 -0700 | [diff] [blame] | 52 | // 3.7. pw_boot_PostMain() |
Armando Montanez | 7009566 | 2020-01-09 14:25:04 -0800 | [diff] [blame] | 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). |
Ewout van Bekkum | fff82ec | 2020-08-21 15:54:28 -0700 | [diff] [blame] | 76 | void StaticMemoryInit(void) { |
Armando Montanez | 7009566 | 2020-01-09 14:25:04 -0800 | [diff] [blame] | 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); |
Armando Montanez | 7009566 | 2020-01-09 14:25:04 -0800 | [diff] [blame] | 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. |
Ewout van Bekkum | fff82ec | 2020-08-21 15:54:28 -0700 | [diff] [blame] | 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(); |
Armando Montanez | 7009566 | 2020-01-09 14:25:04 -0800 | [diff] [blame] | 115 | |
| 116 | // This function is not provided by pw_boot_armv7m, a platform layer, project, |
| 117 | // or application is expected to implement it. |
Ewout van Bekkum | fff82ec | 2020-08-21 15:54:28 -0700 | [diff] [blame] | 118 | pw_boot_PreMainInit(); |
Armando Montanez | 7009566 | 2020-01-09 14:25:04 -0800 | [diff] [blame] | 119 | |
| 120 | // Run main. |
| 121 | main(); |
| 122 | |
Ewout van Bekkum | 738f42c | 2020-08-24 12:55:13 -0700 | [diff] [blame] | 123 | // In case main() returns, invoke this hook. |
| 124 | pw_boot_PostMain(); |
Armando Montanez | 096de55 | 2020-03-23 10:38:18 -0700 | [diff] [blame] | 125 | |
Ewout van Bekkum | 738f42c | 2020-08-24 12:55:13 -0700 | [diff] [blame] | 126 | PW_UNREACHABLE; |
Armando Montanez | 7009566 | 2020-01-09 14:25:04 -0800 | [diff] [blame] | 127 | } |