blob: c1b7307531b2ec0d911524f134ccc563270e5895 [file] [log] [blame]
Armando Montanez70095662020-01-09 14:25:04 -08001// 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 Bekkumfff82ec2020-08-21 15:54:28 -070045// 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 Bekkum738f42c2020-08-24 12:55:13 -070052// 3.7. pw_boot_PostMain()
Armando Montanez70095662020-01-09 14:25:04 -080053
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.
63extern uint8_t _pw_static_init_ram_start;
64extern uint8_t _pw_static_init_ram_end;
65extern uint8_t _pw_static_init_flash_start;
66extern uint8_t _pw_zero_init_ram_start;
67extern uint8_t _pw_zero_init_ram_end;
68
69// Functions called as part of firmware initialization.
70void __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 Bekkumfff82ec2020-08-21 15:54:28 -070076void StaticMemoryInit(void) {
Armando Montanez70095662020-01-09 14:25:04 -080077 // 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 Montanez70095662020-01-09 14:25:04 -080086}
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 Bekkumfff82ec2020-08-21 15:54:28 -070097void 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 Montanez70095662020-01-09 14:25:04 -0800115
116 // This function is not provided by pw_boot_armv7m, a platform layer, project,
117 // or application is expected to implement it.
Ewout van Bekkumfff82ec2020-08-21 15:54:28 -0700118 pw_boot_PreMainInit();
Armando Montanez70095662020-01-09 14:25:04 -0800119
120 // Run main.
121 main();
122
Ewout van Bekkum738f42c2020-08-24 12:55:13 -0700123 // In case main() returns, invoke this hook.
124 pw_boot_PostMain();
Armando Montanez096de552020-03-23 10:38:18 -0700125
Ewout van Bekkum738f42c2020-08-24 12:55:13 -0700126 PW_UNREACHABLE;
Armando Montanez70095662020-01-09 14:25:04 -0800127}