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) |
| 45 | // 3. pw_BootEntry() |
| 46 | // 3.1. Static-init RAM (.data, .bss, C++ constructors) |
| 47 | // 3.2. pw_PreMainInit() |
| 48 | // 3.3. main() |
| 49 | |
| 50 | #include <stdbool.h> |
| 51 | #include <stdint.h> |
| 52 | #include <string.h> |
| 53 | |
| 54 | #include "pw_boot_armv7m/boot.h" |
| 55 | #include "pw_preprocessor/compiler.h" |
| 56 | |
| 57 | // Extern symbols provided by linker script. |
| 58 | // These symbols tell us where various memory sections start and end. |
| 59 | extern uint8_t _pw_static_init_ram_start; |
| 60 | extern uint8_t _pw_static_init_ram_end; |
| 61 | extern uint8_t _pw_static_init_flash_start; |
| 62 | extern uint8_t _pw_zero_init_ram_start; |
| 63 | extern uint8_t _pw_zero_init_ram_end; |
| 64 | |
| 65 | // Functions called as part of firmware initialization. |
| 66 | void __libc_init_array(void); |
| 67 | |
| 68 | // WARNING: Be EXTREMELY careful when running code before this function |
| 69 | // completes. The context before this function violates the C spec |
| 70 | // (Section 6.7.8, paragraph 10 for example, which requires uninitialized static |
| 71 | // values to be zero-initialized). |
| 72 | void StaticInit(void) { |
| 73 | // Static-init RAM (load static values into ram, .data section init). |
| 74 | memcpy(&_pw_static_init_ram_start, |
| 75 | &_pw_static_init_flash_start, |
| 76 | &_pw_static_init_ram_end - &_pw_static_init_ram_start); |
| 77 | |
| 78 | // Zero-init RAM (.bss section init). |
| 79 | memset(&_pw_zero_init_ram_start, |
| 80 | 0, |
| 81 | &_pw_zero_init_ram_end - &_pw_zero_init_ram_start); |
| 82 | |
| 83 | // Call static constructors. |
| 84 | __libc_init_array(); |
| 85 | } |
| 86 | |
| 87 | // WARNING: This code is run immediately upon boot, and performs initialization |
| 88 | // of RAM. Note that code running before this function finishes memory |
| 89 | // initialization will violate the C spec (Section 6.7.8, paragraph 10 for |
| 90 | // example, which requires uninitialized static values to be zero-initialized). |
| 91 | // Be EXTREMELY careful when running code before this function finishes RAM |
| 92 | // initialization. |
| 93 | // |
| 94 | // This function runs immediately at boot because it is at index 1 of the |
| 95 | // interrupt vector table. |
| 96 | void pw_BootEntry() { |
| 97 | StaticInit(); |
| 98 | |
| 99 | // This function is not provided by pw_boot_armv7m, a platform layer, project, |
| 100 | // or application is expected to implement it. |
| 101 | pw_PreMainInit(); |
| 102 | |
| 103 | // Run main. |
| 104 | main(); |
| 105 | |
| 106 | // In case main() returns, just sit here until the device is reset. |
| 107 | while (true) { |
| 108 | } |
| 109 | } |